Pregunta

Estoy usando GCC; __FILE__ devuelve la ruta completa y el nombre del archivo fuente actual: /path/to/file.cpp. ¿Hay alguna manera de obtener solo el nombre del archivo file.cpp (sin su ruta) en tiempo de compilación? ¿Es posible hacer esto de forma portátil? ¿Se puede aplicar la meta programación de plantilla a las cadenas?

Estoy usando esto en una macro de registro de errores. Realmente no quiero que la ruta completa de mi fuente llegue al ejecutable.

¿Fue útil?

Solución

Si está utilizando un programa make, debería poder eliminar el nombre del archivo de antemano y pasarlo como una macro a gcc para usarlo en su programa.

En su archivo MAKE, cambie la línea:

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

Esto le permitirá usar __MYFILE__ en su código en lugar de __FILE__.

El uso del nombre base del archivo fuente ($ <) significa que puede usarlo en reglas generalizadas como " .c.o " ;.

El siguiente código ilustra cómo funciona.

Archivo 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

Archivo src / main.c:

#include <stdio.h>

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

Ejecutar desde el shell:

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

Tenga en cuenta el " file = " línea que contiene solo el nombre base del archivo, no el nombre del directorio.

Otros consejos

Considere este código fuente simple:

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

En Solaris, con GCC 4.3.1, si compilo esto usando:

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

el resultado es 'x.c' Si lo compilo usando:

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

luego __FILE__ se asigna a la ruta completa ('/work1/jleffler/tmp/x.c'). Si lo compilo usando:

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

luego __FILE__ se asigna a '../tmp/x.c'.

Entonces, básicamente, __FILE__ es la ruta del archivo fuente. Si construye con el nombre que desea ver en el objeto, todo está bien.

Si eso es imposible (por cualquier razón), entonces tendrá que entrar en las soluciones sugeridas por otras personas.

No sé de una manera directa. Podrías usar:

#line 1 "filename.c"

en la parte superior del archivo fuente para establecer el valor de __FILE__, pero no estoy seguro de que sea mucho mejor que codificarlo. o simplemente usando un #define para crear tu propia macro.

Otra opción podría ser pasar el nombre de su Makefile usando -D y $ (nombre base del shell $ <)

Editar: si usa una opción #define o -D, debe crear su propio nombre nuevo y no intentar redefinir <=>.

¿Qué hace su macro de registro de errores? Supongo que en algún momento la macro finalmente llama a una función de algún tipo para hacer el registro, ¿por qué no quitar la función llamada del componente de ruta en tiempo de ejecución?

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

Dado que etiquetó CMake, aquí hay una buena solución para agregar a su CMakeLists.txt: (copiado de http://www.cmake.org/pipermail/cmake/ 2011-diciembre / 048281.html ). (Nota: algunos compiladores no admiten COMPILE_DEFINITIONS por archivo, pero funciona 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: Para mi aplicación, necesitaba escapar de la cadena de nombre de archivo de esta manera:

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

Es posible que pueda hacerlo con la metaprogramación de plantilla, pero no hay una forma integrada de hacerlo.

EDITAR: Hm, corrección. Según una página que acabo de ver , GCC usa la ruta que se le da para el archivo. Si se le da el nombre completo, lo incrustará; si solo se le da un pariente, solo lo integrará. Sin embargo, no lo he probado.

Tomando la idea de Glomek, se puede automatizar así:

Archivo fuente x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

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

Línea de compilación (cuidado con las comillas simples fuera de las comillas dobles):

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

El resultado es 'abcd.c'.

Puede asignar __FILE__ a una cadena, y luego llamar a _splitpath () para extraer las piezas. Esta podría ser una solución solo para Windows / MSVC, sinceramente, no lo sé.

Sé que estaba buscando una solución en tiempo de compilación y esta es una solución en tiempo de ejecución, pero pensé que ya que estaba usando el nombre de archivo para hacer un registro de errores (presumiblemente en tiempo de ejecución), esta podría ser una forma sencilla y directa para obtener lo que necesita.

Puede quitar __FILE__ y la tira de la parte de la ruta que no desea (programáticamente). Si basedir satisface sus necesidades, entonces está bien. De lo contrario, obtenga la raíz del directorio fuente de su sistema de compilación, y el resto debería ser factible.

Acabo de recibir el mismo problema; encontré una resolución diferente, solo pensé en compartirla:

En un archivo de encabezado incluido en todos mis otros archivos:

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

Espero que esto también sea útil para otra persona :)

Podría hacerse SOLO mediante programación.

tal vez esto sea útil ...

filename = __FILE__
len  = strlen(filename)

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

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

En algún lugar de 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

Eso es todo. Ahora puedes hacer bonitos mensajes de registro.

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

func src / main.c: 22 - mi error

PS Es mejor desclear en config.h.in - > config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

Así que tu linter no te proporcionará lluvia de errores.

Puedes usar:

bool IsDebugBuild()
{
    return !NDEBUG;
}

O, podría usar NDEBUG en su Macro para activar / desactivar esas rutas de archivos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top