Domanda

Sto usando GCC; __FILE__ restituisce l'intero percorso e nome del file di origine corrente: /path/to/file.cpp. C'è un modo per ottenere solo il nome del file file.cpp (senza il suo percorso) al momento della compilazione? È possibile farlo in modo portatile? La metaprogrammazione del modello può essere applicata alle stringhe?

Lo sto usando in una macro di registrazione degli errori. Non voglio davvero che il percorso completo della mia fonte si faccia strada nell'eseguibile.

È stato utile?

Soluzione

Se stai usando un programma make, dovresti essere in grado di trasferire prima il nome del file e passarlo come macro a gcc per usarlo nel tuo programma.

Nel tuo makefile, cambia la riga:

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

a:

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

Questo ti permetterà di usare __MYFILE__ nel tuo codice invece di __FILE__.

L'uso del nome di base del file sorgente ($ <) significa che puoi usarlo in regole generalizzate come " .c.o " ;.

Il seguente codice illustra come funziona.

Makefile del file:

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

File src / main.c:

#include <stdio.h>

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

Esegui dalla shell:

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

Nota il " file = " riga che contiene solo il nome di base del file, non il dirname.

Altri suggerimenti

Considera questo semplice codice sorgente:

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

Su Solaris, con GCC 4.3.1, se lo compilo usando:

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

l'output è 'x.c' Se lo compilo usando:

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

quindi __FILE__ esegue il mapping al percorso completo ('/work1/jleffler/tmp/x.c'). Se lo compilo usando:

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

quindi __FILE__ esegue il mapping a '../tmp/x.c'.

Quindi, in sostanza, __FILE__ è il percorso del file sorgente. Se costruisci con il nome che vuoi vedere nell'oggetto, va tutto bene.

Se ciò è impossibile (per qualsiasi motivo), dovrai entrare nelle soluzioni suggerite da altre persone.

Non conosco un modo diretto. Puoi usare:

#line 1 "filename.c"

nella parte superiore del file di origine per impostare il valore di __FILE__, ma non sono sicuro che sia molto meglio che codificarlo. o semplicemente usando un #define per creare la tua macro.

Un'altra opzione potrebbe essere quella di passare il nome dal tuo Makefile usando -D e $ (shell basename $ <)

Modifica: se usi #define o l'opzione -D, dovresti creare il tuo nuovo nome e non provare a ridefinire <=>.

Cosa fa la tua macro di registrazione degli errori? Presumo che ad un certo punto la macro alla fine richiama una funzione di qualche tipo per eseguire la registrazione, perché non avere la funzione chiamata strisciata dal componente del percorso in fase di esecuzione?

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

Dato che hai taggato CMake, ecco una soluzione chiara da aggiungere a CMakeLists.txt: (copiato da http://www.cmake.org/pipermail/cmake/ 2011-dicembre / 048281.html ). (Nota: alcuni compilatori non supportano COMPILE_DEFINITIONS per file! Ma funziona con 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: per la mia applicazione avevo bisogno di sfuggire alla stringa del nome file in questo modo:

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

Potresti essere in grado di farlo con la metaprogrammazione dei modelli, ma non esiste un modo integrato per farlo.

EDIT: Hm, correzione. Secondo una pagina che ho appena visto , GCC utilizza il percorso fornito per il file. Se viene dato il nome completo, lo incorporerà; se ne viene dato solo uno relativo, lo incorporerà solo. Non l'ho provato io stesso.

Prendendo l'idea da Glomek, può essere automatizzata in questo modo:

File di origine x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

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

Riga di compilazione (attenzione alle virgolette singole al di fuori delle virgolette doppie):

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

L'output è 'abcd.c'.

È possibile assegnare __FILE__ a una stringa, quindi chiamare _splitpath () per estrarne i pezzi. Questa potrebbe essere una soluzione solo per Windows / MSVC, onestamente non lo so.

So che stavi cercando una soluzione di compilazione e questa è una soluzione di runtime, ma ho pensato che da quando stavi usando il nome file per fare la registrazione degli errori (presumibilmente di runtime), questo potrebbe essere un modo semplice e diretto per offrirti ciò di cui hai bisogno.

Puoi togliere __FILE__ e rimuovere la parte del percorso che non desideri (a livello di programmazione). Se basedir soddisfa le tue esigenze, va bene. Altrimenti, ottieni root dir sorgente dal tuo sistema di compilazione e il resto dovrebbe essere fattibile.

Ho appena ricevuto lo stesso problema; ho trovato una risoluzione diversa, ho pensato di condividerla:

In un file di intestazione incluso in tutti gli altri miei file:

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

Spero che questo sia utile anche a qualcun altro :)

Potrebbe essere fatto SOLO programmaticamente.

forse questo è utile ...

filename = __FILE__
len  = strlen(filename)

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

È facile con 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 ()

Da qualche parte in 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

Questo è tutto. Ora puoi creare graziosi messaggi di log.

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

func src / main.c: 22 - il mio errore

PS È meglio dichiarare in config.h.in - > config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

Quindi la tua linter non fornirà pioggia di errori.

Puoi usare:

bool IsDebugBuild()
{
    return !NDEBUG;
}

In alternativa, è possibile utilizzare NDEBUG nella macro per attivare / disattivare quei percorsi di file.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top