Code Build Optimisation Part 4a – fatal error LNK1170

Original Author: Andy Firth

If you previously followed Code Build Opt Part 4 then you have yourself a fantastic project that incrementally links and everyone is happy… there is a gremlin in this machine however.

Before we continue I should note, this primarily affects Microsofts link.exe (and thus lib.exe) but has also been seen in other commandline archive apps that one might use during development of current gen games (ar.exe for instance).

fatal error LNK1170: line in command file contains 131071 or more characters

What this is referring to is not always obvious so lets first explain what looks like the core problem (it isn’t but keep reading).

Link.exe builds exe’s and libs taking a bunch of parameters and outputting a binary (exe or lib). Often there are a multitude of parameters and the commandline gets too long for a standard command interpreter to allow (10kb in windows cmd.exe for instance). To combat this many commandline apps allow the use of a response file; a file containing all the parameters. So Instead of

Link.exe  /nologo /MACHINE:X64 /Wx  /INCREMENTAL 1.obj 2.obj 3.obj … 5000.obj /out:foo.exe

you would have

Link.exe @response_file /out:foo.exe

In Visual Studio if you enable “Use Library Dependency Inputs” (required for Incremental linking with libs) then VS will drop your library objects into a response file and call link.exe as above.

Now consider that no one calls their cpp files 1.cpp, 2.cpp … 5000.cpp, in fact most of us have something like

c:\project\code\engine\physics\server\ship\footplacement\internal\core\dudefoot.cpp

This will then compile to the object

c:\project\code\obj\engine\physics\server\ship\footplacement\internal\core\dudefoot.obj

So that link with 5000 files in it generates a response file with text in excess of 400k. With this example you would hit LNK1170.

On opening the response file you’d see all your very long paths and assume that reducing their size is the only option. This is what i did for quite a while, jumping through many hoops and doing so every few months to avoid the problem. From googling and talking to other engineers; everyone did the same.

The problem seems to stem from the assumption that a response needs to replace a commandline 1:1. Everything in the response file will append onto the final commandline and your link will (internally) look the same as without the response file. Response files have typically only been a single line in my experience, all the applications i know about that generate them follow this (seemingly as a rule). Even Visual Studio will generate 1 very long 400kb+ line in our example above.

This assumption that a response file is a single line of parameters not true.

From my investigations with 3 linkers and 2 archivers the basic method of resolving a response file is

const int32 max_line_size= 128 << 10;
char line[max_line_size];

do
{
    int32 count= read_line(line, line_size);

    if(count == max_line_size)
    {
        error("fatal error LNK1170: line in command file contains %d or more characters", max_line_size);
    }

    if (count > 0)
    {
        append(link_params, line);
    }
}
while (count > 0)

Older versions and 32bit versions of link.exe use 16kb but still throw an error. Other archivers (AR for instance) fail linking claiming a missing file or bad parameter even when you can see that file exists. These are silently hitting the problem above and simply clipping the characters beyond their internal line limit, which is way worse. For ar (GNU ar 2.17) this limit is 8kb.

This real fix is quite trivial if you generate your own response files; simply add a newline after each appended parameter.

Sadly it seems that if you are currently using the Visual Studio option  “Use Library Dependency Inputs” then you are out of luck, there doesn’t seem to be a way to make VS insert the newline. There are a few options tho:

  1. Generate and manually add a response file to your vcproj, this should be relatively easy to do but it would need updating each time a new file was added to your project.
  2. Switch your libraries build step over to building the response file as the “lib” step vs actually calling lib, then make that step output the response file with newlines.
  3. Write a stub version of the linker that converts the response files to the newline format and calls the real linker.
  4. Specific to Visual Studio, you can look into the “pre-link” step, i haven’t investigated this as we do not use msbuild.

Hopefully this helps anyone else who hits this problem in the future

Series

Part 1  Part 2  Part 3 Part 4

MS Articles:

http://support.microsoft.com/kb/156190

http://connect.microsoft.com/VisualStudio/feedback/details/461987/use-library-dependency-inputs-generates-fatal-error-lnk1170