nodejs/node · error · Exception

Multiple .def files

Error message

Multiple .def files

What it means

GetDefFile scans the target's sources for files ending in '.def' (module-definition files for the MSVC linker). A single .def is accepted and wired into linker flags; more than one is ambiguous and rejected, because the linker can only consume one definition file.

Source

Thrown at tools/gyp/pylib/gyp/msvs_emulation.py:619

        lib(
            "TargetMachine",
            map={"1": "X86", "17": "X64", "3": "ARM"},
            prefix="/MACHINE:",
        )
        lib("AdditionalOptions")
        return libflags

    def GetDefFile(self, gyp_to_build_path):
        """Returns the .def file from sources, if any.  Otherwise returns None."""
        spec = self.spec
        if spec["type"] in ("shared_library", "loadable_module", "executable"):
            def_files = [
                s for s in spec.get("sources", []) if s.lower().endswith(".def")
            ]
            if len(def_files) == 1:
                return gyp_to_build_path(def_files[0])
            elif len(def_files) > 1:
                raise Exception("Multiple .def files")
        return None

    def _GetDefFileAsLdflags(self, ldflags, gyp_to_build_path):
        """.def files get implicitly converted to a ModuleDefinitionFile for the
        linker in the VS generator. Emulate that behaviour here."""
        if def_file := self.GetDefFile(gyp_to_build_path):
            ldflags.append('/DEF:"%s"' % def_file)

    def GetPGDName(self, config, expand_special):
        """Gets the explicitly overridden pgd name for a target or returns None
        if it's not overridden."""
        config = self._TargetConfig(config)
        output_file = self._Setting(("VCLinkerTool", "ProfileGuidedDatabase"), config)
        if output_file:
            output_file = expand_special(
                self.ConvertVSMacros(output_file, config=config)
            )
        return output_file

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Find all '.def' files listed in the target's 'sources' and keep only the one you intend the linker to use.
  2. Remove the extra .def entries (or move them out of sources).
  3. Re-run gyp.

Example fix

// before
'sources': ['lib.def', 'other.def', 'main.c']
// after
'sources': ['lib.def', 'main.c']
Defensive patterns

Strategy: validation

Validate before calling

def_files = [s for s in target_dict.get('sources', []) if s.lower().endswith('.def')]
if target_dict.get('type') in ('shared_library', 'loadable_module', 'executable') and len(def_files) > 1:
    raise ValueError(f'{target_dict["target_name"]}: multiple .def files: {def_files}')

Type guard

def at_most_one_def_file(target_dict: dict) -> bool:
    def_files = [s for s in target_dict.get('sources', []) if s.lower().endswith('.def')]
    return len(def_files) <= 1

Prevention

When it happens

Trigger: A target of type shared_library, loadable_module, or executable has two or more source files whose lowercased name ends with '.def'.

Common situations: Accidentally adding two .def files to sources; merging sources from another target that already contributed a .def; build tooling that drops a generated .def next to a hand-written one.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/5576026abc879c48. Report an issue: GitHub.