Is googletest's test registration mechanism guaranteed to work with MSVC? #4699
Unanswered
ggladilov
asked this question in
Community Help
Replies: 0 comments
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Hi everybody,
I was using
googletest
in multiple projects across different operating systems with various compilers and every time everything worked well (and still is).Recently, I was working on some design proposal in one of my projects that uses similar design decision to what (I think) is used in
googletest
. Specifically, it's about using initialization of non-local non-inline object with static storage duration (global object) as a registration mechanism.In case of
googletest
it seems to have a form of usingTEST_F
macro (in version I'm using it calls toGTEST_TEST_
macro) that expands into a class definition withconst
pointer tostatic ::testing::TestInfo*
data-member variable of nametest_info_
. Straight after class definitiontest_info_
is initialized with call to::testing::internal::MakeAndRegisterTestInfo
.Now, I may miss some details (please correct me if I'm wrong somewhere), but it seems like what I would want to achieve as well: we have some central storage that contains all registered entities of interest. This storage is populated during initialization of global objects in other translation units (with no visible dependency, so these translation units behave as optional plugins). The problem of Static Initialization Order Fiasco is solved via making storage local object of static storage duration that uses static block variables rules (I didn't check specifically if it's true for
googletest
, but my intuition tells me it is).However, as far as I can tell there're multiple caveats with this approach.
C++ standard (I checked C++17 draft version, let me know if it's not applicable to
googletest
, but I think it should; other C++ standards are likely aligned with this) does not guarantee dynamic initialization of non-local non-inline object with static storage duration will be executed prior to the first statement ofmain
function. It can be deferred until later than the first odr-use of the object in question. See C++17 draft 6.6.3 Dynamic initialization of non-local variables [basic.start.dynamic] page 68 (4). I also found related stackoverflow questions (45210561, 45018739). It seems to be a problem to me as the object isn't odr-used - the only purpose of it to be initialized, so registration is triggered.In general this approach may not work when translation units that contains global "register" object are compiled into static library and then linked into final executable with tests. The reason seems to be linker ignoring all the symbols from the static library that are not used (typically true for "register" object). This article describes similar problem. I believe there's a workaround with
--whole-archive
linker option (GNU, Microsoft), though.Doing my little research for a way to implement registration via global objects initialization, such that it reliably works with GCC, Clang and MSVC I found for GCC/Clang one could use
__attribute__((constructor))
(see here) to guarantee initialization will happen beforemain
, but there seem to be no alternative for MSVC (see here). There exists some approach for MSVC using "user initializer section (.CRT$XCU)" (1113409), but I found an example where glib moves away from it because it's not really portable (example).Also, is there a potential risk of the object to be optimized away by the compiler (as unused)? Should some attributes be used here to avoid this? Is there something to be used with MSVC? (note: I saw GCC/Clang
__attribute__((unused))
, but it seems to do the same thing as C++17 [[maybe_unused]] - just omitting a warning, not necessary keeping code executed).So overall, is my understanding correct that
googletest
relies on implementation-defined behavior that global object initialization happens before main and so in theory it may break, e.g. on MSVC, as there're no direct way to instruct it do so?Beta Was this translation helpful? Give feedback.
All reactions