DirectXMath icon indicating copy to clipboard operation
DirectXMath copied to clipboard

XMGLOBALCONST poorly initialized when used within a cpp modules project

Open MartinDew opened this issue 1 year ago • 14 comments

I've been using directx on a personal project that uses modules and had crashes because some of the XMGLOBALCONST declared constants simply don't have the proper values at runtime. In our case it was specifically g_XMInfinity and g_XMOneHalf (The values were 000). The crashes were caused by asserts failing on XMIsInfinity, among others, due to those.

In our case, we use DXTK and simplemath and import it through a Module partition with the following syntax : export import <SimpleMath.h>.

It looks like it has something to do with how __declspec(selectany) reacts when used within modules.

Are we right or is there something we are missing?

Thanks!

MartinDew avatar Oct 10 '24 13:10 MartinDew

Can you link to how you are building the SimpleMath module?

walbourn avatar Oct 14 '24 23:10 walbourn

It might also be a good idea to open your project in VS, and use https://aka.ms/vsfeedback or the "Report a problem..." link. This seems like a bug in the compiler or linker.

walbourn avatar Oct 15 '24 03:10 walbourn

Can you link to how you are building the SimpleMath module?

Not sure if it's what you meant but I am using MSbuild and a VS project. We're using https://github.com/ubisoft/Sharpmake to create our sln and proj files.

MartinDew avatar Oct 15 '24 12:10 MartinDew

Update : I ended up importing DXMath as source into my project and switching the XMGLOBALCONST to be static constexpr fixes the problem.

MartinDew avatar Oct 16 '24 13:10 MartinDew

Can you check the code-generation when using static constexpr. Does it look like it's coming from a shared read-only datasegment, or are you getting a lot of copies of the same data in each module?

walbourn avatar Oct 24 '24 19:10 walbourn

Also it does not appear there is any standard define to know if its being used in a C++20 module or not.

Note you DO NOT have the modify my source. You can use #define XMGLOBALCONST static constexpr before including the headers.

If I were to change the source, I'd probably have to go with (assuming C++20 code gen is not worse with it)

#ifndef XMGLOBALCONST
#if __cplusplus >= 202002L
#define XMGLOBALCONST static constexpr
#elif defined(__GNUC__) && !defined(__MINGW32__)
#define XMGLOBALCONST extern const __attribute__((weak))
#else
#define XMGLOBALCONST extern const __declspec(selectany)
#endif
#endif

My main concern is that math-heavy code would end up with many copies of the constants instead of just one.

walbourn avatar Oct 24 '24 19:10 walbourn

Sorry for the late reply and thanks for your help! I wouldn't honestly know if it causes any more copies. I think that any new variable copying one of the constants would create a copy, but any static constexpr should be there only once in the compiled binaries.

MartinDew avatar Jan 20 '25 23:01 MartinDew

How about defining it as inline constexpr?

MikeMarcin avatar Feb 08 '25 00:02 MikeMarcin

That could probably work.

MartinDew avatar Mar 08 '25 18:03 MartinDew

As a quick look, it appears inline constexpr works, but I'm not sure how to robustly tell as a preprocessor symbol WHEN C++20 modules are being built vs. not. __cpp_modules is always defined for MSVC C++20, and in clang it's not defined unless you #include <version> first.

Note that for now a workaround is:

#define XMGLOBALCONST inline constexpr
#include <DirectXMath.h>

Is there a standard preprocessor symbol that I could use to know if the header is being used in a C++20 module?

walbourn avatar Apr 02 '25 22:04 walbourn

I think it's just strictly better to define it as inline constexpr so long as you have a C++17 or greater compiler language. I don't think you need module detection.

MikeMarcin avatar May 06 '25 23:05 MikeMarcin

I have the same problem. My mini-wrapper around DirectXMath broke after I migrated it to C++20 Modules. All global constants are uninitialized.

KolokolchikovDS avatar Aug 21 '25 18:08 KolokolchikovDS

Is there a standard preprocessor symbol that I could use to know if the header is being used in a C++20 module?

I don't think there would be one since headers are included inside modules technically using hacks, i.e importing them if possible or including them in a global module scope.

Maybe there could be a way to know wether it was imported but yet again I wouldn't bet on it.

MartinDew avatar Sep 20 '25 17:09 MartinDew

I have the same problem. My mini-wrapper around DirectXMath broke after I migrated it to C++20 Modules. All global constants are uninitialized.

You can do what @walbourn suggested and use

module;
 #define XMGLOBALCONST inline constexpr
#include <DirectXMath.h>
module your_module;

On our project we ended up changing the source code but it was because we did before we actually knew that we could just redef it using that method.

MartinDew avatar Sep 20 '25 17:09 MartinDew