What does adding a module definition file via target_sources do?

I recently came across code like this:

if(MSVC)
    target_link_options(foobar PRIVATE 
        /DEF:${CMAKE_CURRENT_SOURCE_DIR}/foobar.def
    )
elseif(MINGW)
    target_sources(foobar PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/foobar.def # ?
    )
endif()

But I don’t see anything in the target_sources documentation covering this behavior?

I don’t think there’s anything specific about target_sources() here. It is just adding foobar.def to the list of sources for the foobar target. What you might be thinking about is how does a *.def file listed in the sources for a target end up being handled. I think CMake recognises *.def files and uses them in place of (or maybe in addition to?) its own generated one, but I haven’t checked the code. I didn’t think that was generator-specific, but I could be wrong about that too. I don’t know if the special handling for MSVC in your example is necessary.

What you might be thinking about is how does a *.def file listed in the sources for a target end up being handled.

Yes that is what I was trying to ask. I tried reading the CMake code but it was unclear to me.

I don’t know if the special handling for MSVC in your example is necessary.

I’m not sure based on my past experience it seems there are minor differences between Ninja / Visual
Studio builds on MSVC:

A .def file is a list of symbols to export from a library in lieu of _EXPORT macros in the source itself. This is just handling the compiler-specific way of telling the compiler what symbols to export from the .dll file.

So what does this code do? Because MinGW uses GCC as a compiler. But GCC doesn’t support module definition files. Does it convert it into a version-script?

if(MINGW)
    target_sources(foobar PRIVATE
        ${CMAKE_CURRENT_SOURCE_DIR}/foobar.def # ?
    )
endif()

If I had to guess, the .def file probably does nothing for MinGW, but all symbols get exported by default for GCC toolchains (please check this, I know this is the case on Unix-based systems, but I don’t know if MinGW does something different). If that’s true, then the code sample you provided probably isn’t doing what you thought, but things appear to work because on MinGW is exporting everything, not just the symbols listed in the .def file. EDIT: I missed this particular aspect in my previous comment.

1 Like

It kind of has to do something for symbol exporting because it’s just a part of the Windows object file format used by the runtime loader. From this SO answer, it looks like there is dlltool which does the .def file work. This is part of the Windows “binutils” and isn’t necessarily part of the toolchain (just like the Linux linker ld is not of any given toolchain; these things are much more “platform”-specified). I do see references in the GCC codebase to dlltool, so presumably any .def file support is done by passing it onto the linker implementation.

1 Like

If I had to guess, the .def file probably does nothing for MinGW, but all symbols get exported by
default for GCC toolchains

I thought the .def file did nothing as well until it caused a regression by removing it from the MINGW build

Also we do set CMAKE_POSITION_INDEPENDENT_CODE to ON and CMAKE_CXX_VISIBILITY_PRESET to hidden.

it looks like there is dlltool which does the .def file work. This is part of the Windows “binutils” and isn’t necessarily part of the toolchain (just like the Linux linker ld is not of any given toolchain; these things are much more “platform”-specified). I do see references in the GCC codebase to dlltool, so presumably any .def file support is done by passing it onto the linker implementation.

That would explain the behavior I have seen :+1: