How to extract the source filename without path and suffix at compile time?

1. gcc builtin function can get the file name of a full path at compile time.

#define __FILENAME__ (__builtin_strrchr(__FILE__, "https://stackoverflow.com/") ? __builtin_strrchr(__FILE__, "https://stackoverflow.com/") + 1 : __FILE__)

or

#define __FILENAME__ (strrchr(__FILE__, "https://stackoverflow.com/") ? strrchr(__FILE__, "https://stackoverflow.com/") + 1 : __FILE__)

2. c++11 constexpr also can do this at compile time.

c++11 constexpr function can only use a return-statement.

example:

#include <stdio.h>

constexpr const char* str_end(const char *str) {
    return *str ? str_end(str + 1) : str;
}

constexpr bool str_slant(const char *str) {
    return *str == "https://stackoverflow.com/" ? true : (*str ? str_slant(str + 1) : false);
}

constexpr const char* r_slant(const char* str) {
    return *str == "https://stackoverflow.com/" ? (str + 1) : r_slant(str - 1);
}
constexpr const char* file_name(const char* str) {
    return str_slant(str) ? r_slant(str_end(str)) : str;
}

int main() {
    constexpr const char *const_file = file_name(__FILE__);
    puts(const_file);
    return 0;
}

source file name is foo/foo1/foo2/foo3/foo4.cpp

use g++ -o foo.exe foo/foo1/foo2/foo3/foo4.cpp -std=c++11 --save-temps to compile this file.

you can see this.

.file   "foo4.cpp"
        .section        .rodata
.LC0:
        .string "foo/foo1/foo2/foo3/foo4.cpp"
        .text
        .globl  main
        .type   main, @function
main:
.LFB4:
        .cfi_startproc
        pushq   %rbp
        .cfi_def_cfa_offset 16
        .cfi_offset 6, -16
        movq    %rsp, %rbp
        .cfi_def_cfa_register 6
        subq    $16, %rsp
        movq    $.LC0+19, -8(%rbp) 
        movl    $.LC0+19, %edi
        call    puts
        movl    $0, %eax
        leave
        .cfi_def_cfa 7, 8
        ret
        .cfi_endproc
.LFE4:
        .size   main, .-main
        .ident  "GCC: (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4"
        .section        .note.GNU-stack,"",@progbits

movl $.LC0+19, %edi .LC0 + 19 is the address of file name string without path and suffix

3. c++14 constexpr function can do this in a simple way

#include <iostream>

constexpr const char* file_name(const char* path) {
    const char* file = path;
    while (*path) {
        if (*path++ == "https://stackoverflow.com/") {
            file = path;
        }
    }
    return file;
}

int main() {
    constexpr const char* file = file_name(__FILE__);
    std::cout << file << std::endl;
    return 0;
}

c++14 constexpr function can use loop and local variable.

the file_name function will replace with a address of const char * at compiler time.
~

Leave a Comment