Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WINRT_SOURCE_LOCATION has ODR checks that prevent mixing cpp17 and cpp20 static libraries #1444

Merged
merged 7 commits into from
Nov 4, 2024

Conversation

dmachaj
Copy link
Contributor

@dmachaj dmachaj commented Nov 1, 2024

Why is this change being made?

Someone is trying to upgrade the cppwinrt version used by a large project that has many static libraries using cppwinrt. Some binaries in that project are mixing static libs with different cpp language versions. (This seems like not a great idea generally but it is the state of the world so to some degree we have to live with it). In those binaries the ODR checks for cppwinrt source_location usage are breaking the build. For good reason, it is not safe to mix this functionality across language versions. This set of changes is aimed at making that upgrade process easier without losing any useful functionality.

Briefly summarize what changed

We already have winrt::impl::slim_source_location which is a lot like std::source_location, minus always containing the very impactful FUNCTION data. This type is powered by the same intrinsics as the STL version so it works as well as the STL library. The existence of this class means that we can avoid the ODR violations by always using winrt::impl::slim_source_location.

Some new macros are used to control what goes into the constructor. cpp20 code that does not suppress source_location will get valid source information passed in. Code that is cpp17, or suppresses this feature, will have zero's passed in. Furthermore, when compiling as _DEBUG this will also include the FUNCTION data, matching previous behavior.

The net result is that there is no more ODR violation because the function signatures are always the same.

For now I have elected not to clean up the WINRT_IMPL_SOURCE_LOCATION_ARGS_NO_DEFAULT macro family. There is only one option so there is no more ODR violation. But removing that would churn a lot of code. I could be convinced to remove it now but only if there is agreement it is worth it and that we won't try to re-add variance later.

How was this change tested?

build_test_all.cmd for both release and debug. I also created a little project that mixes cpp17 and cpp20 libraries. With the latest public release of cppwinrt this project does not build because of the ODR violations. With these changes it builds and runs as expected.

build break with existing cppwinrt

3>Cpp17StaticLib.lib(Cpp17StaticLib.obj) : error LNK2038: mismatch detected for 'WINRT_SOURCE_LOCATION': value 'false' doesn't match value 'slim' in main.ob

cpp17 code

void Cpp17StaticLib()
{
    try
    {
        winrt::check_hresult(E_FAIL);
    }
    catch (const winrt::hresult_error& e)
    {
        wprintf(L"C++17 Static Lib: %ws\n", e.message().c_str());
    }
}

cpp20 code

void Cpp20StaticLib()
{
    try
    {
        winrt::check_hresult(E_FAIL);
    }
    catch (const winrt::hresult_error& e)
    {
        wprintf(L"C++20 Static Lib: %ws\n", e.message().c_str());
    }
}

console exe code

void __stdcall MY_winrt_throw_hresult_handler(uint32_t lineNumber, char const* fileName, char const* functionName, void* returnAddress, winrt::hresult const result) noexcept
{
    wprintf(L"winrt::hresult_error thrown at line %u in %hs in %hs with error code 0x%08X\n", lineNumber, fileName, functionName, (uint32_t)result);
}

int main()
{
    winrt::init_apartment();

    winrt_throw_hresult_handler = MY_winrt_throw_hresult_handler;

    Cpp17StaticLib();
    Cpp20StaticLib();
}

Release output:

winrt::hresult_error thrown at line 0 in (null) in (null) with error code 0x80004005
winrt::hresult_error thrown at line 0 in (null) in (null) with error code 0x80004005
C++17 Static Lib: Unspecified error
winrt::hresult_error thrown at line 7 in %PATH%Cpp20StaticLib\Cpp20StaticLib.cpp in (null) with error code 0x80004005
winrt::hresult_error thrown at line 7 in %PATH%\Cpp20StaticLib\Cpp20StaticLib.cpp in (null) with error code 0x80004005
C++20 Static Lib: Unspecified error

Debug output:

winrt::hresult_error thrown at line 0 in (null) in (null) with error code 0x80004005
winrt::hresult_error thrown at line 0 in (null) in (null) with error code 0x80004005
C++17 Static Lib: Unspecified error
winrt::hresult_error thrown at line 7 in %PATH%\Cpp20StaticLib\Cpp20StaticLib.cpp in Cpp20StaticLib with error code 0x80004005
winrt::hresult_error thrown at line 7 in %PATH%\Cpp20StaticLib\Cpp20StaticLib.cpp in Cpp20StaticLib with error code 0x80004005
C++20 Static Lib: Unspecified error

jonwis
jonwis previously approved these changes Nov 1, 2024
strings/base_macros.h Outdated Show resolved Hide resolved
ChrisGuzak
ChrisGuzak previously approved these changes Nov 2, 2024
Copy link
Member

@ChrisGuzak ChrisGuzak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm in favor of the macro cleanup too.

strings/base_macros.h Outdated Show resolved Hide resolved
strings/base_macros.h Outdated Show resolved Hide resolved
strings/base_macros.h Show resolved Hide resolved
@dmachaj dmachaj dismissed stale reviews from ChrisGuzak and jonwis via f1c3241 November 3, 2024 19:55
@dmachaj dmachaj merged commit e53db0f into master Nov 4, 2024
75 checks passed
@dmachaj dmachaj deleted the user/dmachaj/slim-source-location-cpp17 branch November 4, 2024 22:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants