---
title: "Troubleshooting GoogleTest Linking Issues in Mixed C++/C# Projects"
date: 2025-03-20T00:00:00Z
lastmod: 2026-10-16T19:06:54+02:00
url: https://klimek.link/posts/troubleshooting-googletest-issues-in-mixed-projects/
author: "Marcin Klimek"
source: https://klimek.link/posts/troubleshooting-googletest-issues-in-mixed-projects/
---

# Troubleshooting GoogleTest Linking Issues in Mixed C++/C# Projects

## First part, compiling the code

Integrating GoogleTest into a project that mixes native C++ with managed C++/CLR can get messy, especially when it comes to test detection in Visual Studio's Test Explorer and to linker errors, and recently I ran into both of them at the same time.

### Diagnosing the issue

#### Tests not appearing in Test Explorer

At first my native C++ GoogleTest unit tests were visible in Visual Studio's Test Explorer, but as soon as I enabled C++/CLR they disappeared. It became clear that the test adapter had trouble finding GoogleTest tests once managed code was part of the project.

#### Linker errors and an unexpected Catch2 library

On top of that, the linker started to complain with errors like these:

```
error LNK2038: mismatch detected for '_ITERATOR_DEBUG_LEVEL': value '0' doesn't match value '2'
error LNK2038: mismatch detected for 'RuntimeLibrary': value 'MD_DynamicRelease' doesn't match value 'MDd_DynamicDebug'
```

You get these when Visual Studio tries to link libraries built with conflicting configurations (Debug against Release). The odd part was that `Catch2` ended up in the link even though I had never linked it myself. That's vcpkg's AutoLink feature, which scans for libraries and pulls in the ones that match the configuration, and it made the whole thing a lot harder to untangle.

### Solution

In the end I found out that two additional configuration files were enough to fix it.

#### 1. **packages.config**

Adding this file explicitly specified the correct `GoogleTest` version and restored test detection in Visual Studio's Test Explorer:

```xml
<?xml version="1.0" encoding="utf-8"?>
<packages>
  <package id="Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn" version="1.8.1.7" targetFramework="native" />
</packages>
```

#### 2. **vcpkg.json**

This file declares the dependencies for vcpkg explicitly. I'm not sure it's necessary, but it for sure helped in my dev environment.

```json
{
  "name": "my-project",
  "version-string": "0.1.0",
  "dependencies": [
    "gtest"
  ]
}
```

### Conclusion

It looks like getting `GoogleTest` into a mixed C++ and C++/CLR project brings its own set of problems, and in my case two extra files, `packages.config` and `vcpkg.json`, were what it took to solve them.

## Second part, the great `SEH` exception mystery

The first part was about compiling and linking, and this one is about the runtime. Out of nowhere, `SEH` (Structured Exception Handling) exceptions started to fire the moment the tests ran, which kept even the simplest of them from executing.

> What is the [Structured Exception Handling (SEH)](/posts/structured-exception-handling-seh)

### Initial checks

My first move was to confirm that the Visual Studio debugger was set to Mixed mode (Native + Managed). After that I used breakpoints to narrow the problem down, and eventually it turned out that things went wrong whenever my native tests called into managed code.

The test class has a `SetUp()` method, so I set a breakpoint there. 
```cpp
class UltimateTest : public ::testing::Test
{
protected:
    void SetUp() override
    {
    }
};
```

Nothing broke there, so I removed all the tests and tried the simplest test known to everyone:

```cpp
TEST(BasicTest, Test_Simple) {
  EXPECT_EQ(42, 42);
}
```

No problems with that one, so I added another test based on my `UltimateTest` fixture:

```cpp
TEST_F(UltimateTest, Test_Simple_Fixture) {
  EXPECT_EQ(42, 42);
}
```

Still no issues, and I moved on to a test that calls into a library written in managed C++:

```cpp
TEST_F(UltimateTest, Test_Call_Managed) {
    double result = ManagedMethods::Calc(ManagedMethods::CALCULATE_THIS_THING, 1.0);
    EXPECT_NEAR(result, 3.14159, 1e-5);
}
```

This one wouldn't even stop on the first line, because the `SEH` exception arrived before the code could even think about running. By then I was almost sure that the root of the problem wasn't the adapter or the libraries but something in the project itself. Maybe the dynamic libraries weren't loading properly, or maybe they weren't loading at all.

### Resolving assembly loading issues

To find out, I took over assembly loading myself by overriding `SetUp()` in my test fixture:

```cpp
void SetUp() override {
    System::AppDomain::CurrentDomain->AssemblyResolve += gcnew System::ResolveEventHandler(&UltimateTest::OnAssemblyResolve);
    System::Reflection::Assembly::Load("SpecialManagedLibrary, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
}

static System::Reflection::Assembly^ OnAssemblyResolve(System::Object^ sender, System::ResolveEventArgs^ args) {
    System::String^ assemblyPath = System::IO::Path::Combine(
        System::IO::Path::GetDirectoryName(System::Reflection::Assembly::GetExecutingAssembly()->Location),
        args->Name->Split(',')[0] + ".dll");

    if (System::IO::File::Exists(assemblyPath)) {
        return System::Reflection::Assembly::LoadFrom(assemblyPath);
    } else {
        throw gcnew System::IO::FileNotFoundException("Assembly not found: " + assemblyPath);
    }
}
```

In the output logs I could see assemblies loading and unloading again right away, together with the `"Assembly resolve error:"` message, and that pointed to missing dependencies. Making sure that all of the dependent libraries got copied to the output directory finally fixed it. It took me a while to figure that out.


## Fiddling with `GoogleTest` adapters

While I was chasing this problem I switched the `GoogleTest` adapter three times:

- `Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7`
- `Microsoft.googletest.v140.windesktop.msvcstl.dynamic.rt-dyn.1.8.1.7`
- `Microsoft.googletest.v140.windesktop.msvcstl.static.rt-static.1.8.1.7`

Only `static.rt-dyn` worked with my project. To be honest I was grasping at straws and changing everything I could, since I had no clue what was behind the `SEH` chaos.

For a moment I even considered building my own version of `GoogleTest` from the full sources, just to have the comfort of seeing absolutely everything in the debugger. I ended up pulling version `1.8.1.7` into a separate directory, which gave me a local reference at least. In the end the culprits were mismatched runtime libraries, implicit linking and a few missing dependencies.

Source: https://klimek.link/posts/troubleshooting-googletest-issues-in-mixed-projects/
