Index: lld/COFF/Config.h =================================================================== --- lld/COFF/Config.h +++ lld/COFF/Config.h @@ -179,6 +179,7 @@ bool AppContainer = false; bool MinGW = false; bool WarnLocallyDefinedImported = true; + bool Incremental = true; }; extern Configuration *Config; Index: lld/COFF/Driver.cpp =================================================================== --- lld/COFF/Driver.cpp +++ lld/COFF/Driver.cpp @@ -547,6 +547,12 @@ std::string LibName = getImportName(AsLib); std::string Path = getImplibPath(); + if (!Config->Incremental) { + HandleError(writeImportLibrary(LibName, Path, Exports, Config->Machine, + false, Config->MinGW)); + return; + } + // If the import library already exists, replace it only if the contents // have changed. ErrorOr> OldBuf = MemoryBuffer::getFile(Path); @@ -688,6 +694,29 @@ return Temp; } +// Handle /incremental and emit warnings as necessary. +static void handleIncremental(opt::InputArgList &Args) { + bool WarnIncompatible = true; + opt::Arg *Arg = Args.getLastArg(OPT_incremental, OPT_incremental_no); + if (!Arg) { + WarnIncompatible = false; + } else if (Arg->getOption().getID() == OPT_incremental_no) { + Config->Incremental = false; + return; + } + Config->Incremental = true; + auto ConflictsWithIncremental = [&](StringRef Option, bool Value) { + if (!Value) + return; + if (WarnIncompatible) + warn("ignoring '/INCREMENTAL' due to '" + Option + "' specification"); + Config->Incremental = false; + }; + ConflictsWithIncremental("/OPT:ICF", Config->DoICF); + ConflictsWithIncremental("/OPT:REF", Config->DoGC); + ConflictsWithIncremental("/ORDER", Args.hasArg(OPT_order)); +} + // Create response file contents and invoke the MSVC linker. void LinkerDriver::invokeMSVC(opt::InputArgList &Args) { std::string Rsp = "/nologo\n"; @@ -907,6 +936,7 @@ // Handle /debug if (Args.hasArg(OPT_debug, OPT_debug_dwarf, OPT_debug_ghash)) { Config->Debug = true; + Config->Incremental = true; if (auto *Arg = Args.getLastArg(OPT_debugtype)) Config->DebugTypes = parseDebugType(Arg->getValue()); else @@ -1003,8 +1033,17 @@ Config->Implib = Arg->getValue(); // Handle /opt. - bool DoGC = !Args.hasArg(OPT_debug); - unsigned ICFLevel = 1; // 0: off, 1: limited, 2: on + // There is a complex interaction with /incremental. Incremental linking is + // incompatible with /opt:icf, and /opt:ref. If you specify both /incremental + // and one of those options, you get a warning and incremental linking is + // turned off. If you don't explicitly specify /incremental, it is enabled by + // default, but turned off without a warning if one of the incompatible + // options is specified. Conversely, if you specify /incremental, the defaults + // for /opt:icf and /opt:ref are changed to be compatible with it. + bool ExplicitIncremental = + Args.getLastArg(OPT_incremental, OPT_incremental_no, false); + bool DoGC = !ExplicitIncremental && !Args.hasArg(OPT_debug); + unsigned ICFLevel = ExplicitIncremental ? 0 : 1; // 0: off, 1: limited, 2: on for (auto *Arg : Args.filtered(OPT_opt)) { std::string Str = StringRef(Arg->getValue()).lower(); SmallVector Vec; @@ -1047,6 +1086,11 @@ Config->DoGC = DoGC; Config->DoICF = ICFLevel > 0; + // Handle /incremental. + // Note: This needs to be done after Config options that are incompatible + // with incremental linking have been set. + handleIncremental(Args); + // Handle /lldsavetemps if (Args.hasArg(OPT_lldsavetemps)) Config->SaveTemps = true; Index: lld/COFF/Options.td =================================================================== --- lld/COFF/Options.td +++ lld/COFF/Options.td @@ -103,6 +103,9 @@ defm highentropyva : B<"highentropyva", "Enable 64-bit ASLR (default on 64-bit)", "Disable 64-bit ASLR">; +defm incremental : B<"incremental", + "Link incrementally", + "Perform a full link">; defm largeaddressaware : B<"largeaddressaware", "Enable large addresses (default on 64-bit)", "Disable large addresses (default on 32-bit)">; @@ -148,8 +151,6 @@ def functionpadmin : F<"functionpadmin">; def ignoreidl : F<"ignoreidl">; -def incremental : F<"incremental">; -def no_incremental : F<"incremental:no">; def nologo : F<"nologo">; def throwingnew : F<"throwingnew">; def editandcontinue : F<"editandcontinue">; Index: lld/test/COFF/incremental.test =================================================================== --- /dev/null +++ lld/test/COFF/incremental.test @@ -0,0 +1,75 @@ +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -incremental %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -debug %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=KEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -incremental:no %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -incremental -opt:icf %t.obj 2>&1 \ +# RUN: | FileCheck -check-prefix=WARN-ICF %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -opt:icf %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -check-prefix=WARN-REF %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -incremental -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj +# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj 2>&1 \ +# RUN: | FileCheck -allow-empty -check-prefix=NOWARN %s +# RUN: touch -t 198002011200.00 %t.lib +# RUN: lld-link -out:%t.dll -dll -debug -opt:ref %t.obj +# RUN: ls -l %t.lib | FileCheck -check-prefix=NOKEEP %s + +# NOWARN-NOT: ignoring '/INCREMENTAL' +# WARN-ICF: ignoring '/INCREMENTAL' due to '/OPT:ICF' specification +# WARN-REF: ignoring '/INCREMENTAL' due to '/OPT:REF' specification +# KEEP: {{Feb 1 1980|1980-02-01}} +# NOKEEP-NOT: {{Feb 1 1980|1980-02-01}} Index: lld/test/COFF/unchanged-importlib.test =================================================================== --- lld/test/COFF/unchanged-importlib.test +++ /dev/null @@ -1,7 +0,0 @@ -# RUN: yaml2obj < %p/Inputs/export.yaml > %t.obj -# RUN: lld-link -out:%t.dll -dll %t.obj -# RUN: touch -t 198002011200.00 %t.lib -# RUN: lld-link -out:%t.dll -dll %t.obj -# RUN: ls -l %t.lib | FileCheck --check-prefix=CHECK %s - -# CHECK: {{Feb 1 1980|1980-02-01}}