Question

J'utilise GCC; __FILE__ renvoie le chemin complet et le nom du fichier source actuel: /path/to/file.cpp. Existe-t-il un moyen d'obtenir uniquement le nom du fichier file.cpp (sans son chemin) au moment de la compilation? Est-il possible de le faire de manière portable? La méta-programmation par modèle peut-elle être appliquée aux chaînes?

Je l’utilise dans une macro de journalisation d’erreurs. Je ne veux vraiment pas que le chemin complet de ma source se glisse dans l'exécutable.

Était-ce utile?

La solution

Si vous utilisez un programme make, vous devriez pouvoir créer le nom de fichier au préalable et le transmettre sous forme de macro à gcc pour qu'il soit utilisé dans votre programme.

Dans votre makefile, changez la ligne:

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

Ceci vous permettra d'utiliser __MYFILE__ dans votre code au lieu de __FILE__.

L'utilisation du nom de base du fichier source ($ <) signifie que vous pouvez l'utiliser dans des règles généralisées telles que & ".c.o &";.

Le code suivant illustre son fonctionnement.

Fichier Make:

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

Fichier src / main.c:

#include <stdio.h>

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

Exécuter à partir du shell:

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

Notez le " fichier = " ligne qui contient uniquement le nom de base du fichier, pas le nom de répertoire.

Autres conseils

Considérez ce code source simple:

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

Sous Solaris, avec GCC 4.3.1, si je le compile à l’aide de:

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

le résultat est 'x.c' si je le compile avec:

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

alors __FILE__ correspond au chemin complet ('/work1/jleffler/tmp/x.c'). Si je le compile en utilisant:

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

alors __FILE__ est mappé sur '../tmp/x.c'.

Donc, fondamentalement, __FILE__ est le chemin du fichier source. Si vous construisez avec le nom que vous voulez voir dans l'objet, tout va bien.

Si cela est impossible (pour une raison quelconque), vous devrez entrer dans les corrections suggérées par d'autres personnes.

Je ne connais pas de voie directe. Vous pouvez utiliser:

#line 1 "filename.c"

en haut du fichier source pour définir la valeur __FILE__, mais je ne suis pas sûr que ce soit beaucoup mieux que de le coder en dur. ou simplement en utilisant un #define pour créer votre propre macro.

Une autre option pourrait être de passer le nom de votre Makefile en utilisant -D et $ (nom de base du shell $ <)

Éditer: Si vous utilisez une option #define ou -D, vous devez créer votre propre nouveau nom et ne pas essayer de redéfinir <=>.

Que fait votre macro de journalisation des erreurs? Je présume qu'à un moment donné, la macro appelle éventuellement une fonction quelconque pour effectuer la journalisation. Pourquoi ne pas laisser la bande de fonction appelée masquer le composant chemin au moment de l'exécution?

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

Puisque vous avez tagué CMake, voici une solution intéressante à ajouter à votre CMakeLists.txt: (copie de http://www.cmake.org/pipermail/cmake/ 2011-décembre / 048281.html ). (Remarque: certains compilateurs ne prennent pas en charge COMPILE_DEFINITIONS par fichier! Mais cela fonctionne avec 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})

Remarque: pour mon application, j'avais besoin d'échapper à la chaîne de nom de fichier comme ceci:

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

Vous pourrez peut-être le faire avec une métaprogrammation de modèle, mais il n'y a pas de moyen intégré de le faire.

EDIT: Hm, correction. Selon une page que je viens de voir , GCC utilise le chemin fourni pour le fichier. Si on lui donne le nom complet, ça l'intégrera; si c'est seulement un parent, ça l'intégrera. Je ne l’ai pas essayé moi-même cependant.

En prenant l’idée de Glomek, elle peut être automatisée de la manière suivante:

Fichier source x.c

#line 1 MY_FILE_NAME
#include <stdio.h>

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

Ligne de compilation (attention aux guillemets simples en dehors des guillemets):

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

La sortie est 'abcd.c'.

Vous pouvez affecter __FILE__ à une chaîne, puis appeler _splitpath () pour en extraire les morceaux. Cela pourrait être une solution uniquement Windows / MSVC, honnêtement, je ne sais pas.

Je sais que vous recherchiez une solution au moment de la compilation et qu’il s’agit d’une solution au moment de l’exécution, mais j’imaginais que, puisque vous utilisiez le nom de fichier pour enregistrer les erreurs (probablement à l’exécution), cela pourrait être un moyen simple et direct. pour vous procurer ce dont vous avez besoin.

Vous pouvez enlever __FILE__ et la bande de la partie du chemin que vous ne voulez pas (par programme). Si basedir répond à vos besoins, alors tout va bien. Sinon, récupérez la racine du répertoire source de votre système de génération, et le reste devrait être faisable.

Je viens d'avoir le même problème; trouvé une résolution différente, je pensais juste que je la partagerais:

Dans un fichier d'en-tête inclus dans tous mes autres fichiers:

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

J'espère que cela sera utile à quelqu'un d'autre également:)

Peut être effectué UNIQUEMENT par programme.

peut-être que cela est utile ...

filename = __FILE__
len  = strlen(filename)

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

C’est facile avec 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 ()

Quelque part dans 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

C'est ça. Vous pouvez maintenant créer de jolis messages de journal.

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

func src / main.c: 22 - mon erreur

PS Il est préférable de désactiver dans config.h.in - > config.h

#ifndef __RELATIVE_FILE_PATH__
#define __RELATIVE_FILE_PATH__ __FILE__
#endif

Ainsi, votre navigateur ne fournira pas une pluie d’erreurs.

Vous pouvez utiliser:

bool IsDebugBuild()
{
    return !NDEBUG;
}

Vous pouvez également utiliser NDEBUG dans votre macro pour activer / désactiver ces chemins de fichiers.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top