Pergunta

Eu estou usando GCC; __FILE__ retorna caminho inteiro do arquivo de origem atual e nome: /path/to/file.cpp. Existe uma maneira de obter apenas file.cpp o nome do arquivo (sem o caminho) em tempo de compilação? É possível fazer isso de uma maneira portátil? Pode template programação meta ser aplicada às cordas?

Eu estou usando isso em um macro registro de erros. Eu realmente não quero caminho completo da minha fonte de fazer o seu caminho para o executável.

Foi útil?

Solução

Se você estiver usando um programa de marca, você deve ser capaz de munge o nome do arquivo de antemão e passá-lo como uma macro para gcc para ser usado em seu programa.

Em seu makefile, altere a linha:

file.o: file.c
    gcc -c -o file.o src/file.c

para:

file.o: src/file.c
    gcc "-D__MYFILE__=\"`basename $<`\"" -c -o file.o src/file.c

Isto irá permitir que você use __MYFILE__ em seu código em vez de __FILE__.

O uso do nome base do arquivo de origem ($ <) significa que você pode usá-lo em regras generalizadas como ".c.o".

O código a seguir ilustra como funciona.

makefile arquivo:

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 File / main.c:

#include <stdio.h>

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

Executar a partir do shell:

pax@pax-desktop:~$ mainprog
file = main.c
pax@pax-desktop:~$

Observe o "file =" linha que contém apenas o nome base do arquivo, não o dirname.

Outras dicas

Considere este código-fonte simples:

#include <stdio.h>
int main(void)
{
    puts(__FILE__);
    return(0);
}

No Solaris, com o GCC 4.3.1, se eu compilar este usando:

gcc -o x x.c && ./x

a saída é 'x.c' Se eu compilá-lo usando:

gcc -o x $PWD/x.c && ./x

então __FILE__ mapeia para o caminho completo ( '/work1/jleffler/tmp/x.c'). Se eu compilá-lo usando:

gcc -o x ../tmp/x.c && ./x

então __FILE__ mapeia para '../tmp/x.c'.

Então, basicamente, __FILE__ é o caminho do arquivo de origem. Se você construir com o nome que você quer ver no objeto, está tudo bem.

Se isso for impossível (por qualquer motivo), então você vai ter que entrar as correções sugeridas por outras pessoas.

Eu não sei de uma maneira direta. Você pode usar:

#line 1 "filename.c"

no topo do arquivo de origem para definir o valor de __FILE__, mas não estou certo de que isso é muito melhor do que difícil codificação-lo. ou simplesmente usando um #define para criar sua própria macro.

Outra opção poderia ser a de passar o nome do seu Makefile usando -D e US $ (shell basename $ <)

Edit:. Se você usar um #define ou a opção -D, você deve criar o seu próprio nome novo e não tentar __FILE__ redefine

O que o seu erro de registro macro fazer? Eu presumiria em algum momento o macro, eventualmente, chama uma função de algum tipo, a fim de fazer o registro, porque não têm a função chamada tira fora do caminho componente em tempo de execução?

#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
}

Uma vez que você marcou CMake, aqui está uma solução elegante para adicionar à sua CMakeLists.txt: (Copiado do http://www.cmake.org/pipermail/cmake/ 2011-dezembro / 048281.html ). (Nota: alguns compiladores não suportam COMPILE_DEFINITIONS por arquivo, mas ele funciona com o 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})

Nota: Para a minha candidatura eu precisava para escapar da seqüência de nome de arquivo como este:

COMPILE_DEFINITIONS "MYSRCNAME=\"${b}\"")

Você pode ser capaz de fazê-lo com metaprogramming modelo, mas não há built-in maneira de fazê-lo.

EDIT: Hm, correção. De acordo com a uma página Eu só vi , GCC utiliza o caminho que é dado para o arquivo. Se é dado o nome completo, vai incorporá-lo; se ele só é dado a um parente, ele só vai incorporar isso. Eu não tentei me embora.

Tomando a idéia de Glomek, ele pode ser automatizado como este:

Fonte arquivo x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

int main(void)
{
    puts(__FILE__);
    return(0);
}

linha Compilation (cuidado com as aspas simples fora as aspas):

gcc -DMY_FILE_NAME='"abcd.c"' -o x x.c

A saída é 'abcd.c'.

Você pode atribuir __FILE__ para uma cadeia, e depois chamar _splitpath () para rasgar os pedaços fora dele. Isso pode ser um MSVC-única solução / Windows, honestamente, eu não sei.

Eu sei que você estava procurando uma solução em tempo de compilação e esta é uma solução de tempo de execução, mas eu percebi que desde que você estava usando o nome do arquivo para fazer (em tempo de execução presumivelmente) o registo de erros, esta poderia ser uma maneira simples e direta para você o que você precisa.

Você pode tomar __FILE__ ea tira para fora da parte de caminho que você não quer (programaticamente). Se satisfaz basedir suas necessidades, então tudo bem. Caso contrário, obter raiz dir fonte do seu sistema de compilação, eo resto deve ser factível.

Apenas tenho o mesmo problema; encontrada uma resolução diferente, apenas pensei que eu iria partilhá-la:

Em um arquivo de cabeçalho incluído em todos os meus outros arquivos:

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

Hope isso é útil para outra pessoa também:)

só poderia ser feito por meio de programação.

talvez isso seja útil ...

filename = __FILE__
len  = strlen(filename)

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

É fácil com 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 ()

Em algum lugar 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

É isso. Agora você pode fazer mensagens de log bonitas.

#define ..._LOG_HEADER(target) \
  fprintf(target, "%s %s:%u - ", __func__, __RELATIVE_FILE_PATH__, __LINE__);

func src / main.c: 22 - meu erro

PS É melhor declear em config.h.in -> config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

Portanto, o seu linter Wan't fornecer chuva de erros.

Você pode usar:

bool IsDebugBuild()
{
    return !NDEBUG;
}

Ou, você poderia usar NDEBUG em sua macro para ligar / desligar esses caminhos de arquivo.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top