1

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?

Ted Klein Bergman
  • 9,146
  • 4
  • 29
  • 50
  • The identifier `__MAIN__` is implementation reserved, you must not use it. Also, are you sure you really want to do this? A Python module compares better to a shared library than to individual C++ source files; whatever it is you are actually trying to achieve can probably be done some better way. – Baum mit Augen Apr 29 '18 at 12:42
  • Since you know which file the value of `__MAIN__` is set to, why not just set `__MAIN__` for that one file and use a simple `#ifdef __MAIN__ ... #endif`? Also, [macros with two underscores are reserved for the implementation](https://stackoverflow.com/questions/224397/why-do-people-use-double-underscore-so-much-in-c). – Andrew Henle Apr 29 '18 at 12:43
  • Related: [`__func__` not replaced in preprocessed output](https://stackoverflow.com/q/27899436/509868) – anatolyg Apr 29 '18 at 12:43
  • This is not the right way to do it... Just include the right main file along your library files in your compilation target. Different languages, different paradigms and this paradigm should stay in python. – Jazzwave06 Apr 29 '18 at 12:46
  • @BaummitAugen I'm not sure this is the best way, but I'm frequently in the situation where I'd like to change entry point, just like I would do in python, so it seemed like a natural way to do it. I'm sure however that there are better alternatives and am positive to hear about them as well – Ted Klein Bergman Apr 29 '18 at 12:46
  • If you want to switch, it's because you have different executables. See how cmake (https://cmake.org/cmake/help/v3.0/manual/cmake-buildsystem.7.html) does it. Also, if you want a dynamic entry point, why don't you provide a main that switch on its first parameter? – Jazzwave06 Apr 29 '18 at 12:48
  • [Jesse Chisholm's answer](https://stackoverflow.com/a/23763798/189205) which you linked is wrong. – interjay Apr 29 '18 at 12:49

2 Answers2

3

#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).

Vittorio Romeo
  • 90,666
  • 33
  • 258
  • 416
0

I would like to set a flag like "InSingleFileTest" in compiler parameters, for EXP: -D InSingleFileTest, while I'm in a single file testing . And use like :

#ifdef InSingleFileTest
int main(...){};
#endif

Maybe this is a standard way in C++ to do a single file testing.