Bug: EntryPoint.h defines functions in a header, causing potential ODR violations
Description
The current EntryPoint.h defines WinMain and main directly inside a header file. While #pragma once prevents re-inclusion within the same translation unit, it does not protect across multiple translation units. Each .cpp file that includes this header is its own translation unit, so if a user accidentally includes EntryPoint.h in more than one .cpp file, the linker will throw a cryptic duplicate symbol error:
error LNK2005: _main already defined in Main.obj
error LNK2005: _WinMain already defined in Main.obj
This can be especially confusing for beginners who may not immediately understand why the linker is complaining.
Steps to Reproduce
- Create a new Walnut project
- Create a second
.cpp file and include EntryPoint.h in it
- Build the project
- Observe the linker error with no helpful diagnostic message
Suggested Fix
Move the WinMain and main definitions into a dedicated EntryPoint.cpp file, and keep only the extern int VX_Main(int argc, char* argv[]); declaration in the header:
EntryPoint.h
#pragma once
extern int VX_Main(int argc, char* argv[]);
EntryPoint.cpp
#include "EntryPoint.h"
#ifdef WL_PLATFORM_WINDOWS
#include <Windows.h>
int WINAPI WinMain(...) { return VX_Main(__argc, __argv); }
int main(int argc, char* argv[]) { return VX_Main(argc, argv); }
#else
int main(int argc, char* argv[]) { return VX_Main(argc, argv); }
#endif
This follows the fundamental C++ rule of declarations in headers, definitions in source files, and eliminates the ODR risk entirely.
Additional Notes
An alternative mitigation (short of moving to a .cpp) is an opt-in macro guard that produces a clear #error message if the header is misused — but this still cannot fully prevent the problem across translation units. The .cpp approach is the only complete fix.
Thanks for the great framework!
Bug: EntryPoint.h defines functions in a header, causing potential ODR violations
Description
The current
EntryPoint.hdefinesWinMainandmaindirectly inside a header file. While#pragma onceprevents re-inclusion within the same translation unit, it does not protect across multiple translation units. Each.cppfile that includes this header is its own translation unit, so if a user accidentally includesEntryPoint.hin more than one.cppfile, the linker will throw a cryptic duplicate symbol error:This can be especially confusing for beginners who may not immediately understand why the linker is complaining.
Steps to Reproduce
.cppfile and includeEntryPoint.hin itSuggested Fix
Move the
WinMainandmaindefinitions into a dedicatedEntryPoint.cppfile, and keep only theextern int VX_Main(int argc, char* argv[]);declaration in the header:EntryPoint.h
EntryPoint.cpp
This follows the fundamental C++ rule of declarations in headers, definitions in source files, and eliminates the ODR risk entirely.
Additional Notes
An alternative mitigation (short of moving to a
.cpp) is an opt-in macro guard that produces a clear#errormessage if the header is misused — but this still cannot fully prevent the problem across translation units. The.cppapproach is the only complete fix.Thanks for the great framework!