Макрос __FILE__ показывает полный путь - PullRequest
141 голосов
/ 13 декабря 2011

Стандартный предопределенный MACRO __FILE__, доступный в C, показывает полный путь к файлу. Есть ли способ сократить путь? Я имею в виду вместо

/full/path/to/file.c

Понятно

to/file.c

или

file.c

Ответы [ 22 ]

3 голосов
/ 19 декабря 2018

Немного опоздал на вечеринку, но для GCC посмотрите на вариант -ffile-prefix-map=old=new:

При компиляции файлов, находящихся в каталоге old , запишите любые ссылки для них в результате компиляции, как будто файлы находились в каталог новый вместо. Указание этой опции эквивалентно указав все отдельные опции -f*-prefix-map. Это можно использовать сделать воспроизводимые сборки, которые не зависят от местоположения. Смотрите также -fmacro-prefix-map и -fdebug-prefix-map.

Так что для моих Jenkins сборок я добавлю -ffile-prefix-map=${WORKSPACE}/=/ и еще один, чтобы удалить префикс установки локального пакета dev.

ПРИМЕЧАНИЕ К сожалению, опция -ffile-prefix-map доступна только в GCC 8 и далее, как и -fmacro-prefix-map, который, , я думаю , выполняет часть __FILE__. Например, для GCC 5 у нас есть только -fdebug-prefix-map, который не влияет на __FILE__.

3 голосов
/ 13 декабря 2011

Небольшая разница в том, что предложил @ red1ynx, заключается в создании следующего макроса:

#define SET_THIS_FILE_NAME() \
    static const char* const THIS_FILE_NAME = \
        strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__;

В каждом из ваших файлов .c (pp) добавьте:

SET_THIS_FILE_NAME();

Тогдавы можете ссылаться на THIS_FILE_NAME вместо __FILE__:

printf("%s\n", THIS_FILE_NAME);

Это означает, что построение выполняется один раз для каждого файла .c (pp) вместо каждого обращения к макросу.

Он ограничен использованием только из файлов .c (pp) и будет непригоден для использования из заголовочных файлов.

3 голосов
/ 17 июля 2013

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

Это легко сделать, определив статическую глобальную переменную в файле .h .Это определение дает отдельные и независимые переменные в каждом файле .cpp , который включает .h .Чтобы обеспечить многопоточность, необходимо, чтобы переменная (и) также была локальной (TLS).

Одна переменная хранит имя файла (сокращенное).Другой содержит необрезанное значение, которое дал __FILE__.Файл h:

static __declspec( thread ) const char* fileAndThreadLocal_strFilePath = NULL;
static __declspec( thread ) const char* fileAndThreadLocal_strFileName = NULL;

Сам макрос вызывает метод со всей логикой:

#define __FILENAME__ \
    GetSourceFileName(__FILE__, fileAndThreadLocal_strFilePath, fileAndThreadLocal_strFileName)

И функция реализована следующим образом:

const char* GetSourceFileName(const char* strFilePath, 
                              const char*& rstrFilePathHolder, 
                              const char*& rstrFileNameHolder)
{
    if(strFilePath != rstrFilePathHolder)
    {
        // 
        // This if works in 2 cases: 
        // - when first time called in the cpp (ordinary case) or
        // - when the macro __FILENAME__ is used in both h and cpp files 
        //   and so the method is consequentially called 
        //     once with strFilePath == "UserPath/HeaderFileThatUsesMyMACRO.h" and 
        //     once with strFilePath == "UserPath/CPPFileThatUsesMyMACRO.cpp"
        //
        rstrFileNameHolder = removePath(strFilePath);
        rstrFilePathHolder = strFilePath;
    }
    return rstrFileNameHolder;
}

RemovePath () может быть реализован по-разному, но быстрый и простой, кажется, с strrchr:

const char* removePath(const char* path)
{
    const char* pDelimeter = strrchr (path, '\\');
    if (pDelimeter)
        path = pDelimeter+1;

    pDelimeter = strrchr (path, '/');
    if (pDelimeter)
        path = pDelimeter+1;

    return path;
}
2 голосов
/ 12 июня 2015

Попробуйте

#pragma push_macro("__FILE__")
#define __FILE__ "foobar.c"

после операторов include в исходном файле и добавьте

#pragma pop_macro("__FILE__")

в конце вашего исходного файла.

2 голосов
/ 06 мая 2013

просто надеюсь немного улучшить макрос FILE:

#define FILE (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)

это ловит / и \, как просил Царек Томчак, и это прекрасно работает в моей смешанной среде.

1 голос
/ 01 марта 2019

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

Хотя это не 'Я не могу дать точного ответа, что автор выразил свое желание для , так как он предполагает использование CMake , это довольно близко.Жаль, что никто не упоминал об этом раньше, так как это сэкономило бы мне массу времени.

OPTION(CMAKE_USE_RELATIVE_PATHS "If true, cmake will use relative paths" ON)

Установка значения переменной выше ON сгенерирует команду построения в формате:

cd /ugly/absolute/path/to/project/build/src && 
    gcc <.. other flags ..> -c ../../src/path/to/source.c

В результате макрос __FILE__ преобразуется в ../../src/path/to/source.c

CMake документация

Остерегайтесь предупреждения на странице документации, хотя:

Использовать относительные пути (может не работать!).

Не гарантируется работа во всех случаях, но в моем случае это работало - CMake 3.13 + gcc 4.5

1 голос
/ 13 марта 2018

Вот переносимая функция, которая работает как для Linux (путь '/'), так и для Windows (сочетание '\' и '/').
Компилируется с gcc, clang и против

#include <string.h>
#include <stdio.h>

const char* GetFileName(const char *path)
{
    const char *name = NULL, *tmp = NULL;
    if (path && *path) {
        name = strrchr(path, '/');
        tmp = strrchr(path, '\\');
        if (tmp) {
             return name && name > tmp ? name + 1 : tmp + 1;
        }
    }
    return name ? name + 1 : path;
}

int main() {
    const char *name = NULL, *path = NULL;

    path = __FILE__;
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path ="/tmp/device.log";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:\\Downloads\\crisis.avi";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:\\Downloads/nda.pdf";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = "C:/Downloads\\word.doc";
    name = GetFileName(path);
    printf("path: %s, filename: %s\n", path, name);

    path = NULL;
    name = GetFileName(NULL);
    printf("path: %s, filename: %s\n", path, name);

    path = "";
    name = GetFileName("");
    printf("path: %s, filename: %s\n", path, name);

    return 0;
}

Стандартный вывод:

path: test.c, filename: test.c
path: /tmp/device.log, filename: device.log
path: C:\Downloads\crisis.avi, filename: crisis.avi
path: C:\Downloads/nda.pdf, filename: nda.pdf
path: C:/Downloads\word.doc, filename: word.doc
path: (null), filename: (null)
path: , filename: 
0 голосов
/ 04 июля 2019

Я использую то же решение с @Patrick's answer в течение многих лет.

У него небольшая проблема, когда полный путь содержит символьную ссылку.

Лучшее решение.

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined -D'__FILE__=\"$(subst $(realpath ${CMAKE_SOURCE_DIR})/,,$(abspath $<))\"'")

Зачем это использовать?

  • -Wno-builtin-macro-redefined, чтобы отключить предупреждения компилятора о переопределении макроса __FILE__.

    Для тех компиляторов, которые не поддерживают это, см. Надежный способ ниже.

  • Удалите путь проекта из пути к файлу реальное требование.Вам не понравится тратить время на то, чтобы узнать, где находится файл header.h, src/foo/header.h или src/bar/header.h.

  • Мы должны удалить макрос __FILE__ в cmake файл конфигурации.

    Этот макрос используется в большинстве существующих кодов.Просто переопределите его, чтобы освободить.

    Компиляторы, такие как gcc, предопределяют этот макрос из аргументов командной строки.И полный путь записывается в makefile с, сгенерированном cmake.

  • Требуется жесткий код в CMAKE_*_FLAGS.

    Есть некоторые команды для добавления опций или определений компилятора в более позднюю версию, например add_definitions() и add_compile_definitions().Эти команды проанализируют функции make, такие как subst, прежде чем применять их к исходным файлам.Это не то, что нам нужно.

Надежный способ для -Wno-builtin-macro-redefined.

include(CheckCCompilerFlag)
check_c_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_C_WNO_BUILTIN_MACRO_REDEFINED)
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-builtin-macro-redefined SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
if (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-builtin-macro-redefined")
endif (SUPPORT_CXX_WNO_BUILTIN_MACRO_REDEFINED)

Не забудьте удалить этот параметр компилятора из строки set(*_FLAGS ... -D__FILE__=...).

0 голосов
/ 19 марта 2019
#include <algorithm>
#include <string>
using namespace std;
string f( __FILE__ );
f = string( (find(f.rbegin(), f.rend(), '/')+1).base() + 1, f.end() );

// searches for the '/' from the back, transfers the reverse iterator 
// into a forward iterator and constructs a new sting with both
0 голосов
/ 24 июля 2018

Вот решение, использующее вычисление времени компиляции:

constexpr auto* getFileName(const char* const path)
{
    const auto* startPosition = path;
    for (const auto* currentCharacter = path;*currentCharacter != '\0'; ++currentCharacter)
    {
        if (*currentCharacter == '\\' || *currentCharacter == '/')
        {
            startPosition = currentCharacter;
        }
    }

    if (startPosition != path)
    {
        ++startPosition;
    }

    return startPosition;
}

std::cout << getFileName(__FILE__);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...