Invoking lld for PE/COFF (Windows) linking

I build llvm/clang/lld from source on Windows using mingw-64/gcc-6.3. I use clang++ both to test clang targeting gcc and clang targeting VC++. When using clang targeting VC++ I use the appropriate target triple when compiling and am trying to use lld to link the object file(s) into an exe. To do that I use the clang option "-fuse-ld=lld" when linking. According to the llvm doc on using lld with PE/COFF on Windows at
https://lld.llvm.org/windows_support.html:

"LLD supports Windows operating system. When invoked as lld-link.exe or with -flavor link, the driver for Windows operating system is used to parse command line options, and it drives further linking processes. LLD accepts almost all command line options that the linker shipped with Microsoft Visual C++ (link.exe) supports."

Unfortunately with clang++ attempting to use "-fuse-ld=lld-link" when linking outputs:

"clang++.exe: error: unsupported value 'lld_link' for -linker option"

So I must use "-fuse-ld=lld". Does this mean that I should be passing "-flavor link" to the lld linker ? If so, how do I do that ? If not, what do I do to have lld work with PE/COFF linking rather than ELF linking ?

I have attempted to pass to the clang++ when linking:

1) "-flavor link", which outputs:
clang++.exe: error: unknown argument: '-flavor'
clang++.exe: error: no such file or directory: 'link'

2) -flavor=link", which outputs:
clang++.exe: error: unknown argument: '-flavor=link'

3) -Wl,-flavor,link, which outputs
C:\Programming\VersionControl\bninja_installed_clang\bin\lld: error: unknown argument: -flavor

4) -Wl,-flavor=link, which outputs
C:\Programming\VersionControl\bninja_installed_clang\bin\lld: error: unknown argument: -flavor=link

What is the "magic" invocation that will allow me to invoke the lld linker from the clang++ command, but get the linker to work in PE/COFF mode rather than in ELF mode, so it will link object files created by clang targeting VC++ ?

If clang is targeting VC++, then -fuse-ld=lld should be enough to make it run lld-link.exe, and you won’t need to set the flavor or do anything special to get PE/COFF files.

This example worked for me:

$ cat t.cpp
#include
int main() { std::cout << “hello world\n”; }

$ clang++ t.cpp -fuse-ld=lld -o t.exe && ./t.exe

hello world

Unfortunately, we don’t have a GNU-ld compatible command line interface for the COFF port of LLD, if that’s what you’re having trouble with. This is something I personally think we should add, but don’t have time to pursue.

If clang is targeting VC++, then -fuse-ld=lld should be enough to make
it run lld-link.exe, and you won't need to set the flavor or do anything
special to get PE/COFF files.

I build LLVM/cClang/lld with mingw-64/gcc-6.3, not with VC++. If I compile with clang using the target triple of "-target i686-pc-windows-msvc" and "-fmsc-version=1900" for VC++14, the compilation is successful and clang creates a VC++ compatible object file. If I subsequently link using clang++ with link option "-fuse-ld=lld" I get as output:

"lld: error: Windows targets are not supported on the ELF frontend: i386pe"

If I add the "-target i686-pc-windows-msvc" to the clang++ link command, the clang++ command just hangs and never completes.

If clang is targeting VC++, then -fuse-ld=lld should be enough to make
it run lld-link.exe, and you won't need to set the flavor or do anything
special to get PE/COFF files.

I build LLVM/cClang/lld with mingw-64/gcc-6.3, not with VC++.

Of course that should be:

"I build LLVM/clang/lld with mingw-64/gcc-6.3, not with VC++."

If clang is targeting VC++, then -fuse-ld=lld should be enough to make
it run lld-link.exe, and you won't need to set the flavor or do anything
special to get PE/COFF files.

This example worked for me:

$ cat t.cpp
#include <iostream>
int main() { std::cout << "hello world\n"; }

$ clang++ t.cpp -fuse-ld=lld -o t.exe && ./t.exe
hello world

Unfortunately, we don't have a GNU-ld compatible command line interface
for the COFF port of LLD, if that's what you're having trouble with.
This is something I personally think we should add, but don't have time
to pursue.

Are you saying that once lld is built with mingw-64/gcc on Windows it is impossible to tell it to handle PE/COFF files when invoking it from clang++ using the -fuse-ld=lld parameter ? That would indeed be limiting, considering that on Windows I can build clang either with mingw-64/gcc or with Visual C++, and the -target parameter allows clang to generate the appropriate object files.

The logic to construct an lld-link command line is part of the MSVC
toolchain in the clang driver, so you can get clang++ to make a coff file
if you tell it you're targetting MSVC like this:
$ clang++ t.cpp -fuse-ld=lld -o t.exe --target=x86_64-windows-msvc

Of course, that will look for libraries and headers in the wrong places if
you really want to target mingw. If I split it up like this, I get link
errors:
$ clang++ -c t.cpp -o t.o --target=x86_64-windows-gnu
$ clang++ t.o -o t.exe --target=x86_64-windows-msvc -fuse-ld=lld
C:\src\llvm-project\build_mingw\bin\lld-link.exe: warning: t.o: undefined
symbol: _ZNSt8ios_base4InitC1Ev
C:\src\llvm-project\build_mingw\bin\lld-link.exe: warning: t.o: undefined
symbol: _ZNSt8ios_base4InitD1Ev
C:\src\llvm-project\build_mingw\bin\lld-link.exe: warning: t.o: undefined
symbol: __main
C:\src\llvm-project\build_mingw\bin\lld-link.exe: warning: t.o: undefined
symbol: _ZSt4cout
C:\src\llvm-project\build_mingw\bin\lld-link.exe: warning: t.o: undefined
symbol: _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
error: link failed
clang++.exe: error: linker command failed with exit code 1 (use -v to see
invocation)

If you pile on enough link options, you can probably make it work, but at
that point you're basically reconstructing a link.exe / lld-link.exe
command line. To fix this, someone should add mingw toolchain logic to
clang's driver to support constructing lld-link command lines.

    Are you saying that once lld is built with mingw-64/gcc on Windows
    it is impossible to tell it to handle PE/COFF files when invoking it
    from clang++ using the -fuse-ld=lld parameter ? That would indeed be
    limiting, considering that on Windows I can build clang either with
    mingw-64/gcc or with Visual C++, and the -target parameter allows
    clang to generate the appropriate object files.

The logic to construct an lld-link command line is part of the MSVC
toolchain in the clang driver, so you can get clang++ to make a coff
file if you tell it you're targetting MSVC like this:
$ clang++ t.cpp -fuse-ld=lld -o t.exe --target=x86_64-windows-msvc

Of course, that will look for libraries and headers in the wrong places
if you really want to target mingw. If I split it up like this, I get
link errors:
$ clang++ -c t.cpp -o t.o --target=x86_64-windows-gnu
$ clang++ t.o -o t.exe --target=x86_64-windows-msvc -fuse-ld=lld

Actually just doing:

clang++ -c t.cpp -o t.o --target=x86_64-windows-msvc -fmsc-version=1900
clang++ t.o -o t.exe --target=x86_64-windows-msvc -fuse-ld=lld

is not working for me. The first invocation works but the second just hangs and never completes. Should it work ? If not, how can I invoke the second to make it work properly ?

Is it actually running lld-link.exe? Does lld-link.exe exist next to
clang++.exe? If you add -###, what linker command line is clang trying to
run?

"C:/Programming/VersionControl/bninja_installed_clang/bin/clang++" -o "C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.exe" -Wl,--start-group "C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.obj" -Wl,-Bstatic -Wl,-Bdynamic -Wl,--end-group -g --target=i686-pc-windows-msvc -### -fuse-ld=lld

  clang version 5.0.0 (trunk 298890)
  Target: i686-pc-windows-msvc
  Thread model: posix
  InstalledDir: C:\Programming\VersionControl\bninja_installed_clang\bin
"C:\\Programming\\VersionControl\\bninja_installed_clang\\bin\\lld-link.exe" "-out:C:\\Programming\\VersionControl\\modular-boost\\build\\boost\\bin.v2\\libs\\preprocessor\\test\\config_info.test\\clang-linux-5.0cl\\debug\\address-model-32\\config_info.exe" "-defaultlib:libcmt" "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\lib" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.14393.0\\ucrt\\x86" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.14393.0\\um\\x86" "-nologo" "-debug" "--start-group" "C:\\Programming\\VersionControl\\modular-boost\\build\\boost\\bin.v2\\libs\\preprocessor\\test\\config_info.test\\clang-linux-5.0cl\\debug\\address-model-32\\config_info.obj" "-Bstatic" "-Bdynamic" "--end-group"

"C:/Programming/VersionControl/bninja_installed_clang/bin/clang++" -o "C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.exe" -Wl,--start-group "C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.obj" -Wl,-Bstatic -Wl,-Bdynamic -Wl,--end-group -g --target=i686-pc-windows-msvc -### -fuse-ld=lld

clang version 5.0.0 (trunk 298890)
Target: i686-pc-windows-msvc
Thread model: posix
InstalledDir: C:\Programming\VersionControl\bninja_installed_clang\bin

"C:\\Programming\\VersionControl\\bninja_installed_clang\\bin\\lld-link.exe" "-out:C:\\Programming\\VersionControl\\modular-boost\\build\\boost\\bin.v2\\libs\\preprocessor\\test\\config_info.test\\clang-linux-5.0cl\\debug\\address-model-32\\config_info.exe" "-defaultlib:libcmt" "-libpath:C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\lib" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.14393.0\\ucrt\\x86" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.14393.0\\um\\x86" "-nologo" "-debug" "--start-group" "C:\\Programming\\VersionControl\\modular-boost\\build\\boost\\bin.v2\\libs\\preprocessor\\test\\config_info.test\\clang-linux-5.0cl\\de

When I actually try to run the lld-link command as:

C:\Programming\VersionControl\bninja_installed_clang\bin\lld-link.exe -out:C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.exe -defaultlib:libcmt "-libpath:C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\lib" "-libpath:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0\ucrt\x86" "-libpath:C:\Program Files (x86)\Windows Kits\10\Lib\10.0.14393.0\um\x86" -nologo -debug --start-group C:\Programming\VersionControl\modular-boost\build\boost\bin.v2\libs\preprocessor\test\config_info.test\clang-linux-5.0cl\debug\address-model-32\config_info.obj -Bstatic -Bdynamic --end-group

I get for output in a Windows command window:

C:\Programming\VersionControl\bninja_installed_clang\bin\lld-link.exe: warning:
ignoring unknown argument: --start-group
C:\Programming\VersionControl\bninja_installed_clang\bin\lld-link.exe: warning:
ignoring unknown argument: -Bstatic
C:\Programming\VersionControl\bninja_installed_clang\bin\lld-link.exe: warning:
ignoring unknown argument: -Bdynamic
C:\Programming\VersionControl\bninja_installed_clang\bin\lld-link.exe: warning:
ignoring unknown argument: --end-group

and then nothing further and lld_link.exe just hangs and never completes. So it looks to me that lld_link, in it effort to link PE/COFF (Windows) files created by clang++ targeting VC++, has some sort of bug.

Perhaps, you'll find these useful:
https://sourceforge.net/p/mingw-w64/bugs/597
https://github.com/lhmouse/mcfgthread/issues/21

(awson is me)

Perhaps, you'll find these useful:
MinGW-w64 - for 32 and 64 bit Windows / Bugs / #597 LLD built with mingw-w64-based GCC deadlocks
Deadlock in exit(0) (LLD) · Issue #21 · lhmouse/mcfgthread · GitHub

I appreciate the links.