docs: def _build_gdef(ufo, skipExportGlyphs=None):
      """Build a GDEF table statement (GlyphClassDef and LigatureCaretByPos).
  
      Building GlyphClassDef requires anchor propagation or user care to work as
      expected, as Glyphs.app also looks at anchors for classification:
  
      * Base: any glyph that has an attaching anchor (such as "top"; "_top" does
        not count) and is neither classified as Ligature nor Mark using the
        definitions below;
      * Ligature: if subCategory is "Ligature" and the glyph has at least one
        attaching anchor;
      * Mark: if category is "Mark" and subCategory is either "Nonspacing" or
        "Spacing Combining";
      * Compound: never assigned by Glyphs.app.
  
      See:
  
      * https://github.com/googlei18n/glyphsLib/issues/85
      * https://github.com/googlei18n/glyphsLib/pull/100#issuecomment-275430289
      """
      from glyphsLib import glyphdata
  
      bases, ligatures, marks, carets = set(), set(), set(), {}
      category_key = GLYPHLIB_PREFIX + "category"
      subCategory_key = GLYPHLIB_PREFIX + "subCategory"
  
      for glyph in ufo:
          # Do not generate any entries for non-export glyphs, as looking them up on
          # compilation will fail.
          if skipExportGlyphs is not None:
              if glyph.name in skipExportGlyphs:
                  continue
  
          has_attaching_anchor = False
          for anchor in glyph.anchors:
              name = anchor.name
              if name and not name.startswith("_"):
                  has_attaching_anchor = True
              if name and name.startswith("caret_") and "x" in anchor:
                  carets.setdefault(glyph.name, []).append(round(anchor["x"]))
  
          # First check glyph.lib for category/subCategory overrides. Otherwise,
          # use global values from GlyphData.
          glyphinfo = glyphdata.get_glyph(glyph.name)
          category = glyph.lib.get(category_key) or glyphinfo.category
          subCategory = glyph.lib.get(subCategory_key) or glyphinfo.subCategory
  
          if subCategory == "Ligature" and has_attaching_anchor:
              ligatures.add(glyph.name)
          elif category == "Mark" and (
              subCategory == "Nonspacing" or subCategory == "Spacing Combining"
          ):
              marks.add(glyph.name)
          elif has_attaching_anchor:
              bases.add(glyph.name)
  
      if not any((bases, ligatures, marks, carets)):
          return None
  
      def fmt(g):
          return ("[%s]" % " ".join(sorted(g, key=ufo.glyphOrder.index))) if g else ""
  
      lines = [
          "table GDEF {",
          "  # automatic",
          "  GlyphClassDef",
          "    %s, # Base" % fmt(bases),
          "    %s, # Liga" % fmt(ligatures),
          "    %s, # Mark" % fmt(marks),
          "    ;",
      ]
      for glyph, caretPos in sorted(carets.items()):
          lines.append(
              "  LigatureCaretByPos %s %s;"
              % (glyph, " ".join(unicode(p) for p in sorted(caretPos)))
          )
      lines.append("} GDEF;")
  
      return "\n".join(lines)