ld unable to find iostreams functions under MSYS2

If I include iostreams I receive linking errors running under MSYS2 targeting x86_64:

cmake . -GNinja
ninja

... undefined reference to std::ios_base::Init, etc. If I try to use cout it fails to find those methods as well.

I’ve tried to explicitly link in libstdc++ to no avail.

Do you have example code you could share?

#include <Windows.h>
#include <iostream>
using namespace std;

int APIENTRY wWinMain(
	_In_	 HINSTANCE	hInstance,
	_In_opt_ HINSTANCE	hPrevInstance,
	_In_	 LPWSTR		lpCmdLine,
	_In_ 	 int		nCmdShow
) {
    return EXIT_SUCCESS;
}
cmake_minimum_required(VERSION 3.10.2)
project(cmaketest VERSION 0.0.1)

set(CMAKE_MODULE_PATH "cmake")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++2a -municode")

add_executable(cmaketest cmaketest.cc)
target_include_directories(cmaketest PUBLIC "${PROJECT_BINARY_DIR}")
target_link_libraries(cmaketest)
$ ninja
[2/2] Linking CXX executable cmaketest
FAILED: cmaketest
: && /mingw64/bin/CC.exe -std=gnu++2a -municode  CMakeFiles/cmaketest.dir/cmaketest.cc.obj -o cmaketest   && :
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/cmaketest.dir/cmaketest.cc.obj:cmaketest.cc:(.text+0x2b): undefined reference to `std::ios_base::Init::~Init()'
C:/msys64/mingw64/bin/../lib/gcc/x86_64-w64-mingw32/10.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles/cmaketest.dir/cmaketest.cc.obj:cmaketest.cc:(.text+0x5b): undefined reference to `std::ios_base::Init::Init()'
collect2.exe: error: ld returned 1 exit status
ninja: build stopped: subcommand failed.

You must use the C++ compiler. Not sure what CMake thinks about .cc but common source file extensions for C++ are .cpp or .cxx

It seems to use cc.exe but this is wrong

CMake does think it is a C++ file (and I’d assume a C compiler would choke on that gnu++2a standard):

I suspect the toolchain is not working properly. Does it compile on the command line without the -c step in between?

CC -std=gnu++2a -municode -o test cmaketest.cc

cc fails the same way, but x86_64-w64-mingw32-g++ works just fine. I was originally just using x86_64-w64-mingw32-g++ to build it manually.

Hmm. I wonder why CMake is selecting cc.exe rather than the g++ executable. Do you have CXX set in the environment at all?

I don’t, and setting it doesn’t seem to change the behavior of cmake. But in the MSYS2 MinGW shell /mingw64/bin/cc.exe -v indicates that it should be the same compiler. Looking at the compiler invocation I can’t see anything that would change behavior.

Some programs look at the name they are called with and change behavior based on that. For example, gcc foo.cxx works for compilation and fails at the link step just like here:

$ cat foo.cxx
#include <iostream>

int main(int argc, char* argv[]) {
    return 0;
}
$ gcc foo.cxx
/usr/bin/ld: /tmp/cc6G9wwR.o: in function `__static_initialization_and_destruction_0(int, int)':
foo.cxx:(.text+0x35): undefined reference to `std::ios_base::Init::Init()'
/usr/bin/ld: foo.cxx:(.text+0x44): undefined reference to `std::ios_base::Init::~Init()'
collect2: error: ld returned 1 exit status

So I think figuring out why CMake thinks cc.exe is your C++ compiler is what needs investigated.

@brad.king Have you seen this?

I’ve seen this happen when someone puts CXX=gcc or CXX=clang in their environment, or uses -DCMAKE_CXX_COMPILER= with one of those.

In this case, CXX=CC might do it.

That seems to be the issue, most easily solved (due to how MinGW sets up the env) by using source_file_properties to set LANGUAGE CXX for the files.

Can .cc be added as a C++ extension? Unsure if you’d suggest I make a ticket for this.

.cc is a C++ extension (see here). And CMake already does think it’s compiling C++ code:

The problem is that a C compiler is being selected as your C++ compiler. That is what needs to be figured out.

On one MSYS2 installation this works but on another it doesn’t. I can’t figure out why cc.exe is being run, and the environments were prepared more or less the same way using MSYS2’s package manager.

On one environment, the files properties changed the behavior.