Search code examples
c++macrosconstexprclang++entry-point

Emulating if __name__ == __main__ in c++ causes error "function-like macro is not defined"


I'm writing a simple build file with bash, that is suppose to make it easy for me to switch entry point by emulating Python's

if __name__ == '__main__':
    main()

My idea was to include a macro by passing -D __MAIN__=\"$MAIN_FILE\" to clang++, where MAIN_FILE is a file you specify when running the build script. Then I'll just have to compare the macro __MAIN__ to the predefined standard macro __FILE__ for each source file. Something like this:

#if equals(__FILE__, __MAIN__)
    int main()
    {
        /* code */
        return 0;
    }
#endif
    

The problem I'm encountering is making the function equals to work in compile-time. Reading up on this it seems like it should be possible to define a constexpr function that compares the strings in compile-time (at least according to this and this answer).

However, whenever I try to create such a function (or copying the code from here or here), I get the following error:

error: function-like macro 'equals' is not defined

Which seems strange to me since it's neither a macro or undefined. I couldn't find a solution when searching for the error message either.

Here's the full code for reference:

#include <iostream>

constexpr bool equals(const char* a, const char* b)
{
    return *a == *b && (*a == '\0' || equals(a + 1, b + 1));
}

#if equals(__FILE__, __MAIN__)
    int main()
    {
        std::cout << "Running " << __MAIN__ << std::endl;
        return 0;
    }
#endif

Compiled with:

clang++ main.cpp -std=c++14 -D __MAIN__="fullpath/main.cpp"

What's causing this error and how can I solve my problem?


Solution

  • #if and #endif are preprocessor directives - the preprocessor runs as part of the compilation step, but it is not aware about C++ as a language.

    You cannot mix and match the preprocessor with C++ features such as constexpr functions.

    If you want this to work, you need to implement your own #define EQUALS macro that checks string equality entirely in the preprocessing step. I'm not sure whether or not it's possible (and worth it).