WINDOWS_EXPORT_ALL_SYMBOLS Exports symbol "__"

I’m using CMake’s WINDOWS_EXPORT_ALL_SYMBOLS property on a long existing codebase that has historically been a static library but I’m hoping to convert it quickly into a DLL (even if just temporarily). This option seems like the perfect method to test the waters but I’m running into a strange problem.

Basically, when I do this I get this error:

warning LNK4022: cannot find unique match for symbol '__'

When I open the generated exports.def, I find this line:

__ DATA

I’m guessing this is some artifact of the codebase, not an error in CMake but I was hoping someone might have an idea of what I should look for to fix this. I thought maybe it was an anonymous struct or enum generated by a line like this:

typedef struct { int x; } foo;

or

typedef enum { TEST, TEST2 } bar;

I’ve cleaned up all that nonsense though and I’m still getting the error. Does anyone have an idea what else I might look for? Or better yet, have a more efficient way to pinpoint where this bad symbol name is coming from?

Thanks!

Comment out files in the library until the symbol disappears? I’d bisect it and comment out half of the files. If the error persists, comment out half of the remaining. If not, flip the last comment set around. There may be more than one file doing this, but once you find one culprit, narrowing down what in the source does this could be another round of bisecting the TU source with #if 0 blocks.

I ended up writing a script to use CMake’s DEF generation obj file by obj file to narrow down which one
was the culprit. It turned out to my PCH which was including the PCH of one of our support libraries (who often gives us grief). I managed to excise it from our PCH (PUBLIC vs PRIVATE solved that) but I’m planning to circle around back to that to try and narrow down the culprit and I’ll use your suggestion to identify the bit of code causing the grief.

If I can do that, I’ll probably file a ticket for it. Even if it’s something stupid – high likelihood – it may be something that gives other people grief. I’ll post the script here eventually too in case someone wants to use it for a similar problem.

Thanks for the reply!

For those interested, here’s the python script I used to track down the object file that had the problem symbol:

import subprocess
import os

TEMP_DEF_FILE = r'<path_to_temp_folder>\temp.def'
OBJ_FILE_LIST_FILE = r'<path_to_temp_folder>\temp.objs'
SEARCH_DIR = r'<path_to_root_obj_folder>'
NEEDLE = '<symbol_string_pattern_to_search_for>'

def search_file(file_path: str, needle: str) -> bool:
    with open(file_path, 'r') as file:
        content = file.read()
        if needle in content:
            return True
        else:
            return False


def generate_def_file(def_file_path: str, obj_file_path: str):

    if os.path.exists(OBJ_FILE_LIST_FILE):
        os.remove(OBJ_FILE_LIST_FILE)

    if os.path.exists(def_file_path):
        os.remove(def_file_path)

    with open(OBJ_FILE_LIST_FILE, 'w+') as file:
        file.write(obj_file_path)

    subprocess.run(['cmake',  '-E',  '__create_def', def_file_path, OBJ_FILE_LIST_FILE])


def search_symbols(obj_file_path: str, needle: str) -> bool:
    generate_def_file(TEMP_DEF_FILE, obj_file_path)

    found = search_file(TEMP_DEF_FILE, needle)

    if found:
        print(f"Found {needle} in {obj_file_path}.")

    return found


found = False

for subdir, dirs, files in os.walk(SEARCH_DIR):
    for file in files:
        full_file_path = subdir + "\\" + file
        found = search_symbols(full_file_path, NEEDLE)

        if found:
            break

    if found:
        break

if not found:
    print(f"'{NEEDLE}' was not found in any object file.")

I spent some time digging into what created the __ symbol but the behaviour is strange. It’s coming from a PCH but when I disable the PCH and instead include that PCH header from a normal source file (to speed up the search), the symbol doesn’t appear. Whatever is creating it seems to have to be in a PCH or it won’t create the empty symbol. My best guess is there’s an empty namespace that gets declared (for some stupid reason) in the headers that the PCH includes.

The circumstances are narrow enough that it’d be a pain to recreate the circumstances for a ticket and rare enough that it may not be worth fixing anyways.