diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 81203501..741ade2d 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -46,11 +46,12 @@ jobs:
           libusb-1.0-0-dev
           libhidapi-dev
           libftdi1-dev
-          libreadline-dev
       - name: Configure
         run: >-
           cmake
           -D DEBUG_CMAKE=1
+          -D HAVE_LINUXGPIO=1
+          -D HAVE_LINUXSPI=1
           -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
           -B ../build
       - name: Build
@@ -59,11 +60,18 @@ jobs:
         if: always()
         uses: actions/upload-artifact@v2
         with:
-          name: linux-x86_64
+          name: build-linux-x86_64
           path: |
             build/
             !**/*.d
             !**/*.o
+      - name: Archive executables
+        uses: actions/upload-artifact@v2
+        with:
+          name: avrdude-linux-x86_64
+          path: |
+            build/avrdude
+            build/avrdude.conf
 
   linux:
     runs-on: ubuntu-latest
@@ -96,11 +104,12 @@ jobs:
           libusb-1.0-0-dev:${{matrix.arch}}
           libhidapi-dev:${{matrix.arch}}
           libftdi1-dev:${{matrix.arch}}
-          libreadline-dev:${{matrix.arch}}
       - name: Configure
         run: >-
           cmake
           -D DEBUG_CMAKE=1
+          -D HAVE_LINUXGPIO=1
+          -D HAVE_LINUXSPI=1
           -D CMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
           -D CMAKE_SYSTEM_NAME=Linux
           -D CMAKE_SYSTEM_PROCESSOR=${{matrix.processor}}
@@ -115,11 +124,18 @@ jobs:
         if: always()
         uses: actions/upload-artifact@v2
         with:
-          name: linux-${{matrix.processor}}
+          name: build-linux-${{matrix.processor}}
           path: |
             build/
             !**/*.d
             !**/*.o
+      - name: Archive executables
+        uses: actions/upload-artifact@v2
+        with:
+          name: avrdude-linux-${{matrix.processor}}
+          path: |
+            build/avrdude
+            build/avrdude.conf
 
   macos-x86_64:
     runs-on: macos-latest
@@ -152,11 +168,18 @@ jobs:
         if: always()
         uses: actions/upload-artifact@v2
         with:
-          name: macos-x86_64
+          name: build-macos-x86_64
           path: |
             build/
             !**/*.d
             !**/*.o
+      - name: Archive executables
+        uses: actions/upload-artifact@v2
+        with:
+          name: avrdude-macos-x86_64
+          path: |
+            build/avrdude
+            build/avrdude.conf
 
   msvc:
     runs-on: windows-latest
@@ -196,11 +219,23 @@ jobs:
         if: always()
         uses: actions/upload-artifact@v2
         with:
-          name: msvc-${{matrix.arch}}
+          name: build-msvc-${{matrix.arch}}
           path: |
             build/
             !**/_deps/
             !**/*.obj
+      - name: Move executables
+        run: |
+          mv ../build/RelWithDebInfo/avrdude.exe ../build
+          mv ../build/RelWithDebInfo/avrdude.pdb ../build
+      - name: Archive executables
+        uses: actions/upload-artifact@v2
+        with:
+          name: avrdude-msvc-${{matrix.arch}}
+          path: |
+            build/avrdude.exe
+            build/avrdude.pdb
+            build/avrdude.conf
 
   mingw:
     runs-on: windows-latest
@@ -241,6 +276,13 @@ jobs:
         if: always()
         uses: actions/upload-artifact@v2
         with:
-          name: mingw-${{matrix.env}}
+          name: build-mingw-${{matrix.env}}
           path: |
             build/
+      - name: Archive executables
+        uses: actions/upload-artifact@v2
+        with:
+          name: avrdude-mingw-${{matrix.env}}
+          path: |
+            build/avrdude.exe
+            build/avrdude.conf
diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index f486cec8..cae55264 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -41,7 +41,7 @@ jobs:
         with:
           tag_name: ${{github.ref}}
           release_name: AVRDUDE ${{github.ref}}
-          body: "**[Release Notes:](https://github.com/avrdudes/avrdude/blob/main/NEWS)**"
+          body: "See **[Release Notes](https://github.com/avrdudes/avrdude/blob/main/NEWS)** for changes"
           draft: false
           prerelease: false
 
@@ -58,13 +58,13 @@ jobs:
       - name: Download artifact
         uses: actions/download-artifact@v2
         with:
-          name: msvc-${{matrix.arch}}
+          name: avrdude-msvc-${{matrix.arch}}
 
       - name: Create release asset
         run: >-
           zip -j asset.zip
-          RelWithDebInfo/avrdude.exe
-          RelWithDebInfo/avrdude.pdb
+          avrdude.exe
+          avrdude.pdb
           avrdude.conf
 
       - name: Upload release asset
diff --git a/NEWS b/NEWS
index 1e325db6..f08274d1 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ Changes since version 6.4:
   * New devices supported:
 
     - ATtiny828, ATtiny87, ATtiny167, ATtiny48, ATtiny102, ATtiny104
+    - LGT8F88P, LGT8F168P, LGT8F328P (fixed names of these parts)
 
   * New programmers supported:
 
@@ -22,6 +23,7 @@ Changes since version 6.4:
       passive parts)
     - PicKit4 / SNAP (now also in ISP and PDI mode)
     - Teensy bootloader (PR #802)
+    - Micronucleus bootloader (PR #786)
 
   * Issues fixed:
 
@@ -40,6 +42,9 @@ Changes since version 6.4:
       programmer #813
     - [bug #53180] missing programmer or bad -P option argument
       doesn't result in error message #471
+    - ATmega328P reported as lgt8fx328p #812
+    - [bug #48004] Dead link for linuxgpio in avrdude description #419
+    - Segmentation fault when writing ATtiny104 fuse #823
 
   * Pull requests:
 
@@ -70,6 +75,12 @@ Changes since version 6.4:
     - buspirate: fix invalidScanfArgType_int warning #808
     - Ignore ac_cfg.h.in~ #810
     - Notify open failure #814
+    - Print expected part #817
+    - pindefs: conform to the function declaration #818
+    - Add support for Micronucleus bootloader #786
+    - Remove ac_cfg.h from libavrdude.h #820
+    - CMake: enable dynamic-link library for libavrdude #826
+    - Fix for TPI fuse write (issue #823) #828
 
   * Internals:
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 8fbb21d7..3dfd6778 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -33,6 +33,7 @@ option(HAVE_PARPORT "Enable parallel port support" OFF)
 option(USE_EXTERNAL "Use external libraries from AVRDUDE GitHub repositories" OFF)
 option(USE_LIBUSBWIN32 "Prefer libusb-win32 over libusb" OFF)
 option(DEBUG_CMAKE "Enable debugging output for this CMake project" OFF)
+option(BUILD_SHARED_LIBS "Build shared libraries" OFF)
 
 include(CheckIncludeFile)
 include(CheckSymbolExists)
@@ -476,7 +477,7 @@ endif()
 # Project
 # =====================================
 
-add_library(libavrdude STATIC
+add_library(libavrdude
     ac_cfg.h
     arduino.h
     arduino.c
@@ -585,6 +586,8 @@ add_library(libavrdude STATIC
     ${BISON_Parser_OUTPUTS}
     )
     
+set_target_properties(libavrdude PROPERTIES PREFIX "")
+
 target_include_directories(libavrdude
     PUBLIC
     "${PROJECT_SOURCE_DIR}"
diff --git a/src/avr.c b/src/avr.c
index dd9095e4..68ecc9a4 100644
--- a/src/avr.c
+++ b/src/avr.c
@@ -867,6 +867,11 @@ int avr_write(PROGRAMMER * pgm, AVRPART * p, char * memtype, int size,
   if ((p->flags & AVRPART_HAS_TPI) && m->page_size > 1 &&
       pgm->cmd_tpi != NULL) {
 
+    if (wsize == 1) {
+      /* fuse (configuration) memory: only single byte to write */
+      return avr_write_byte(pgm, p, m, 0, m->buf[0]) == 0? 1: -1;
+    }
+
     while (avr_tpi_poll_nvmbsy(pgm));
 
     /* setup for WORD_WRITE */
@@ -1074,6 +1079,11 @@ static uint8_t get_fuse_bitmask(AVRMEM * m) {
     return 0xFF;
   }
 
+  if (m->op[AVR_OP_WRITE] == NULL ||
+      m->op[AVR_OP_READ] == NULL)
+    // no memory operations provided by configuration, compare directly
+    return 0xFF;
+
   // For fuses, only compare bytes that are actually written *and* read.
   for (i = 0; i < 32; i++) {
     if (m->op[AVR_OP_WRITE]->bit[i].type == AVR_CMDBIT_INPUT)
diff --git a/src/avrdude.1 b/src/avrdude.1
index 0cadf9ab..670ecb55 100644
--- a/src/avrdude.1
+++ b/src/avrdude.1
@@ -106,7 +106,7 @@ be taken about voltage level compatibility. Also, although not strictrly
 required, it is strongly advisable to protect the GPIO pins from 
 overcurrent situations in some way. The simplest would be to just put
 some resistors in series or better yet use a 3-state buffer driver like
-the 74HC244. Have a look at http://kolev.info/avrdude-linuxgpio for a more
+the 74HC244. Have a look at http://kolev.info/blog/2013/01/06/avrdude-linuxgpio/ for a more
 detailed tutorial about using this programmer type.
 .Pp
 Under a Linux installation with direct access to the SPI bus and GPIO
diff --git a/src/avrdude.conf.in b/src/avrdude.conf.in
index 29107feb..2f6042bb 100644
--- a/src/avrdude.conf.in
+++ b/src/avrdude.conf.in
@@ -17953,24 +17953,24 @@ part parent    ".avrdx"
 #------------------------------------------------------------
 
 part parent "m88"
-    id               = "lgt8fx88p";
-    desc             = "LGT8FX88P";
+    id               = "lgt8f88p";
+    desc             = "LGT8F88P";
     signature        = 0x1e 0x93 0x0f;
 
     ocdrev              = 1;
   ;
 
 part parent "m168"
-    id              = "lgt8fx168p";
-    desc            = "LGT8FX168P";
+    id              = "lgt8f168p";
+    desc            = "LGT8F168P";
     signature       = 0x1e 0x94 0x0b;
 
     ocdrev              = 1;
 ;
 
 part parent "m328"
-    id      = "lgt8fx328p";
-    desc    = "LGT8FX328P";
+    id      = "lgt8f328p";
+    desc    = "LGT8F328P";
     signature   = 0x1e 0x95 0x0F;
 
     ocdrev              = 1;
diff --git a/src/avrpart.c b/src/avrpart.c
index 4ebd4eef..3f2461ef 100644
--- a/src/avrpart.c
+++ b/src/avrpart.c
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "ac_cfg.h"
 #include "avrdude.h"
 #include "libavrdude.h"
 
diff --git a/src/config_gram.y b/src/config_gram.y
index d82fae9e..e2a935cf 100644
--- a/src/config_gram.y
+++ b/src/config_gram.y
@@ -294,7 +294,7 @@ prog_def :
         lrmv_d(programmers, existing_prog);
         pgm_free(existing_prog);
       }
-      PUSH(programmers, current_prog);
+      LISTADD(programmers, current_prog);
 //      pgm_fill_old_pins(current_prog); // TODO to be removed if old pin data no longer needed
 //      pgm_display_generic(current_prog, id);
       current_prog = NULL;
@@ -387,7 +387,7 @@ part_def :
         lrmv_d(part_list, existing_part);
         avr_free_part(existing_part);
       }
-      PUSH(part_list, current_part); 
+      LISTADD(part_list, current_part); 
       current_part = NULL; 
     }
 ;
diff --git a/src/confwin.c b/src/confwin.c
index 9624947f..06f18e20 100644
--- a/src/confwin.c
+++ b/src/confwin.c
@@ -17,6 +17,7 @@
  */
 
 
+#include "ac_cfg.h"
 #include "avrdude.h"
 #include "libavrdude.h"
 
diff --git a/src/doc/avrdude.texi b/src/doc/avrdude.texi
index 784e5a56..2ca2f6ed 100644
--- a/src/doc/avrdude.texi
+++ b/src/doc/avrdude.texi
@@ -177,7 +177,7 @@ be taken about voltage level compatibility. Also, although not strictly
 required, it is strongly advisable to protect the GPIO pins from 
 overcurrent situations in some way. The simplest would be to just put
 some resistors in series or better yet use a 3-state buffer driver like
-the 74HC244. Have a look at http://kolev.info/avrdude-linuxgpio for a more
+the 74HC244. Have a look at http://kolev.info/blog/2013/01/06/avrdude-linuxgpio/ for a more
 detailed tutorial about using this programmer type.
 
 Under a Linux installation with direct access to the SPI bus and GPIO
diff --git a/src/lexer.l b/src/lexer.l
index 6e930a1e..2e27a5d4 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -28,6 +28,7 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include "ac_cfg.h"
 #include "avrdude.h"
 #include "libavrdude.h"
 #include "config.h"
diff --git a/src/libavrdude.h b/src/libavrdude.h
index 40b49b53..0a72f678 100644
--- a/src/libavrdude.h
+++ b/src/libavrdude.h
@@ -21,9 +21,6 @@
 #ifndef libavrdude_h
 #define libavrdude_h
 
-/* XXX should go away */
-#include "ac_cfg.h"
-
 #include <stdio.h>
 #include <limits.h>
 #include <stdbool.h>
diff --git a/src/main.c b/src/main.c
index 8bc051a9..35cdb1d5 100644
--- a/src/main.c
+++ b/src/main.c
@@ -366,6 +366,10 @@ int main(int argc, char * argv [])
   char  * homedir;
 #endif
 
+#ifdef _MSC_VER
+  _set_printf_count_output(1);
+#endif
+
   /*
    * Set line buffering for file descriptors so we see stdout and stderr
    * properly interleaved.
@@ -1221,12 +1225,19 @@ int main(int argc, char * argv [])
         if (sig->buf[i] != 0x00)
           zz = 0;
       }
+
+      bool signature_matches =
+          sig->size == 3 &&
+          sig->buf[0] == p->signature[0] &&
+          sig->buf[1] == p->signature[1] &&
+          sig->buf[2] == p->signature[2];
+
       if (quell_progress < 2) {
         AVRPART * part;
 
         part = locate_part_by_signature(part_list, sig->buf, sig->size);
         if (part) {
-          avrdude_message(MSG_INFO, " (probably %s)", part->id);
+          avrdude_message(MSG_INFO, " (probably %s)", signature_matches ? p->id : part->id);
         }
       }
       if (ff || zz) {
@@ -1255,10 +1266,7 @@ int main(int argc, char * argv [])
         }
       }
 
-      if (sig->size != 3 ||
-          sig->buf[0] != p->signature[0] ||
-          sig->buf[1] != p->signature[1] ||
-          sig->buf[2] != p->signature[2]) {
+      if (!signature_matches) {
         avrdude_message(MSG_INFO, "%s: Expected signature for %s is %02X %02X %02X\n",
                         progname, p->desc,
                         p->signature[0], p->signature[1], p->signature[2]);
diff --git a/src/pindefs.c b/src/pindefs.c
index 5acb33fd..f51e5c20 100644
--- a/src/pindefs.c
+++ b/src/pindefs.c
@@ -22,6 +22,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include "ac_cfg.h"
 #include "avrdude.h"
 #include "libavrdude.h"
 
@@ -217,7 +218,7 @@ const char * pinmask_to_str(const pinmask_t * const pinmask) {
  * @param[in] size the number of entries in checklist
  * @returns 0 if all pin definitions are valid, -1 otherwise
  */
-int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, bool output) {
+int pins_check(const struct programmer_t * const pgm, const struct pin_checklist_t * const checklist, const int size, const bool output) {
   static const struct pindef_t no_valid_pins = {{0}, {0}}; // default value if check list does not contain anything else
   int rv = 0; // return value
   int pinname; // loop counter through pinnames
diff --git a/src/update.c b/src/update.c
index 95e1028f..5f00d32d 100644
--- a/src/update.c
+++ b/src/update.c
@@ -25,6 +25,7 @@
 #include <string.h>
 #include <time.h>
 
+#include "ac_cfg.h"
 #include "avrdude.h"
 #include "libavrdude.h"