code: def link(
      self,
      target_desc,
      objects,
      output_filename,
      output_dir=None,
      libraries=None,
      library_dirs=None,
      runtime_library_dirs=None,
      export_symbols=None,
      debug=0,
      extra_preargs=None,
      extra_postargs=None,
      build_temp=None,
      target_lang=None,
  ):
      objects, output_dir = self._fix_object_args(objects, output_dir)
      fixed_args = self._fix_lib_args(
          libraries, library_dirs, runtime_library_dirs
      )
      libraries, library_dirs, runtime_library_dirs = fixed_args
  
      lib_opts = gen_lib_options(
          self, library_dirs, runtime_library_dirs, libraries
      )
      if not isinstance(output_dir, (str, type(None))):
          raise TypeError("'output_dir' must be a string or None")
      if output_dir is not None:
          output_filename = os.path.join(output_dir, output_filename)
  
      if self._need_link(objects, output_filename):
          ld_args = (
              objects
              + self.objects
              + lib_opts
              + ["-o", output_filename]
          )
          if debug:
              ld_args[:0] = ["-g"]
          if extra_preargs:
              ld_args[:0] = extra_preargs
          if extra_postargs:
              ld_args.extend(extra_postargs)
          self.mkpath(os.path.dirname(output_filename))
          try:
              # Select a linker based on context: linker_exe when
              # building an executable or linker_so (with shared options)
              # when building a shared library.
              building_exe = target_desc == CCompiler.EXECUTABLE
              linker = (
                  self.linker_exe if building_exe else self.linker_so
              )[:]
  
              if target_lang == "c++" and self.compiler_cxx:
                  env, linker_ne = _split_env(linker)
                  aix, linker_na = _split_aix(linker_ne)
                  _, compiler_cxx_ne = _split_env(self.compiler_cxx)
                  _, linker_exe_ne = _split_env(self.linker_exe)
  
                  params = _linker_params(linker_na, linker_exe_ne)
                  linker = env + aix + compiler_cxx_ne + params
  
              linker = compiler_fixup(linker, ld_args)
  
              self.spawn(linker + ld_args)
          except DistutilsExecError as msg:
              raise LinkError(msg)
      else:
          log.debug("skipping %s (up-to-date)", output_filename)
  
imports: import os
  import sys
  import re
  import shlex
  import itertools
  from .None import sysconfig
  from ._modified import newer
  from .ccompiler import CCompiler, gen_preprocess_options, gen_lib_options
  from .errors import DistutilsExecError, CompileError, LibError, LinkError
  from ._log import log
  from ._macos_compat import compiler_fixup
label_desc: Use image node_id 4 for calling the UnixCCompiler obj's underlying member method code with example usage: obj.link(target_desc, objects, output_filename, output_dir, libraries, library_dirs, runtime_library_dirs, export_symbols, debug, extra_preargs, extra_postargs, build_temp, target_lang) without return types