Index: /trunk/src/kmk/kmk_cc_exec.c
===================================================================
--- /trunk/src/kmk/kmk_cc_exec.c	(revision 2801)
+++ /trunk/src/kmk/kmk_cc_exec.c	(revision 2802)
@@ -556,7 +556,7 @@
     kKmkCcEvalInstr_assign_define,
 
-    /** export variable1 [variable2...] - KMKCCEVALEXPORT. */
+    /** export variable1 [variable2...] - KMKCCEVALVARIABLES. */
     kKmkCcEvalInstr_export,
-    /** unexport variable1 [variable2...] - KMKCCEVALEXPORT. */
+    /** unexport variable1 [variable2...] - KMKCCEVALVARIABLES. */
     kKmkCcEvalInstr_unexport,
     /** export - KMKCCEVALCORE. */
@@ -564,4 +564,7 @@
     /** unexport - KMKCCEVALCORE. */
     kKmkCcEvalInstr_unexport_all,
+    /** [local|override] undefine - KMKCCEVALVARIABLES. */
+    kKmkCcEvalInstr_undefine,
+
 
     /** [else] ifdef variable - KMKCCEVALIFDEFPLAIN. */
@@ -688,7 +691,8 @@
 
 /**
- * Instruction format for kKmkCcEvalInstr_export and kKmkCcEvalInstr_unexport.
- */
-typedef struct kmk_cc_eval_export
+ * Instruction format for kKmkCcEvalInstr_export, kKmkCcEvalInstr_unexport and
+ * kKmkCcEvalInstr_undefine.
+ */
+typedef struct kmk_cc_eval_variables
 {
     /** The core instruction. */
@@ -696,4 +700,6 @@
     /** The number of variables named in aVars. */
     uint32_t                cVars;
+    /** Whether the 'local' qualifier was used (undefine only). */
+    uint8_t                 fLocal;
     /** Pointer to the next instruction. */
     PKMKCCEVALCORE          pNext;
@@ -702,8 +708,8 @@
      * @remarks Plain text names are in variable_strcache. */
     KMKCCEXPSUBPROGORPLAIN  aVars[1];
-} KMKCCEVALEXPORT;
-typedef KMKCCEVALEXPORT *PKMKCCEVALEXPORT;
-/** Calculates the size of an KMKCCEVALEXPORT structure for @a a_cVars. */
-#define KMKCCEVALEXPORT_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVPATH, aVars, a_cVars)
+} KMKCCEVALVARIABLES;
+typedef KMKCCEVALVARIABLES *PKMKCCEVALVARIABLES;
+/** Calculates the size of an KMKCCEVALVARIABLES structure for @a a_cVars. */
+#define KMKCCEVALVARIABLES_SIZE(a_cVars) KMK_CC_SIZEOF_VAR_STRUCT(KMKCCEVALVARIABLES, aVars, a_cVars)
 
 /**
@@ -1115,5 +1121,5 @@
     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'o', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* override */
     KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'p', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* private */
-    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine */
+    KMK_CC_EVAL_BM_OR(g_abEvalCcChars, 'u', KMK_CC_EVAL_CH_1ST_IN_VARIABLE_KEYWORD); /* undefine, unexport */
 
     /* Assignment punctuation and recipe stuff. */
@@ -3391,6 +3397,12 @@
          && (a_pchLine)[15] == (a_pszWord)[15])
 #endif
+
+/** See if the given string match a constant string. */
+#define KMK_CC_STRCMP_CONST(a_pchLeft, a_cchLeft, a_pszConst, a_cchConst) \
+    (   (a_cchLeft) == (a_cchConst) \
+     && KMK_CC_WORD_COMP_CONST_##a_cchConst(a_pchLeft, a_pszConst) )
+
 /** See if a starting of a given length starts with a constant word. */
-#define KMK_CC_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \
+#define KMK_CC_EVAL_WORD_COMP_IS_EOL(a_pCompiler, a_pchLine, a_cchLine) \
     (   (a_cchLine) == 0 \
      || KMK_CC_EVAL_IS_SPACE((a_pchLine)[0]) \
@@ -3398,5 +3410,5 @@
 
 /** See if a starting of a given length starts with a constant word. */
-#define KMK_CC_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \
+#define KMK_CC_EVAL_WORD_COMP_CONST(a_pCompiler, a_pchLine, a_cchLine, a_pszWord, a_cchWord) \
     (    (a_cchLine) >= (a_cchWord) \
       && (   (a_cchLine) == (a_cchWord) \
@@ -5187,23 +5199,23 @@
             cchLeft -= 2;
 
-            if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
+            if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
                 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 1 /* in else */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
                 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 1 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
                 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
                 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 0 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
                 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 1 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
                 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
                 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 1 /* in else */, 0 /* positive */);
 
@@ -5300,5 +5312,5 @@
                                                                                   KMKCCEVALINCLUDE_SIZE(cWords));
             pInstr->Core.enmOpcode = enmOpcode;
-            pInstr->Core.iLine     = 0;
+            pInstr->Core.iLine     = pCompiler->iLine;
             pInstr->cFiles         = cWords;
             kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aFiles);
@@ -5330,5 +5342,5 @@
                                                 const char *pchColon, size_t cchLeft, unsigned fQualifiers)
 {
-    kmk_cc_eval_fatal(pCompiler, pchWord0, "recipe handling not implemented yet");
+    kmk_cc_eval_fatal(pCompiler, pchWord0, "recipe handling not implemented yet (#1)");
     return 1;
 }
@@ -5338,5 +5350,5 @@
                                                    const char *pchWord, size_t cchLeft, unsigned fQualifiers)
 {
-    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet");
+    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#2)");
     return 1;
 }
@@ -5345,5 +5357,5 @@
 static void kmk_cc_eval_handle_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pszEqual, const char *pchWord, size_t cchLeft)
 {
-    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet");
+    kmk_cc_eval_fatal(pCompiler, pchWord, "recipe handling not implemented yet (#3)");
 }
 
@@ -5358,5 +5370,46 @@
 
 /**
- * Parses a 'undefine variable [..]' expression.
+ * Common worker for handling export (non-assign), undefine and unexport.
+ *
+ * For instructions using the KMKCCEVALVARIABLES structure.
+ *
+ * @returns 1 to indicate we've handled a keyword (see
+ *          kmk_cc_eval_try_handle_keyword).
+ * @param   pCompiler   The compiler state.
+ * @param   pchWord     First non-space chare after the keyword.
+ * @param   cchLeft     The number of chars left to parse on this line.
+ * @param   fQualifiers The qualifiers.
+ */
+static int kmk_cc_eval_do_with_variable_list(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
+                                             KMKCCEVALINSTR enmOpcode, unsigned fQualifiers)
+{
+    if (cchLeft)
+    {
+        /*
+         * Parse the variable name list.  GNU make is using normal word
+         * handling here, so we can share code with the include directives.
+         */
+        unsigned cWords = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
+        KMK_CC_EVAL_DPRINTF(("%s: cWords=%d\n", g_apszEvalInstrNms[enmOpcode], cWords));
+        if (cWords)
+        {
+            PKMKCCEVALVARIABLES pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
+                                                                                      KMKCCEVALVARIABLES_SIZE(cWords));
+            pInstr->Core.enmOpcode = enmOpcode;
+            pInstr->Core.iLine     = pCompiler->iLine;
+            pInstr->cVars         = cWords;
+            kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars);
+            kmk_cc_block_realign(pCompiler->ppBlockTail);
+        }
+        else
+            KMK_CC_ASSERT(0);
+    }
+    /* else: NOP */
+    return 1;
+}
+
+
+/**
+ * Parses a '[qualifiers] undefine variable [..]' expression.
  *
  * A 'undefine' directive is final, any qualifiers must preceed it.  So, we just
@@ -5372,15 +5425,20 @@
 static int kmk_cc_eval_do_var_undefine(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
 {
-    kmk_cc_eval_fatal(pCompiler, pchWord, "undefine handling not implemented yet");
-    return 1;
-}
-
-
-/**
- * Parses a 'define variable' expression.
- *
- * A 'define' directive is final, any qualifiers must preceed it.  So, we just
- * have to extract the variable name now, well and find the corresponding
- * 'endef'.
+    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
+    if (!cchLeft)
+        kmk_cc_eval_fatal(pCompiler, pchWord, "undefine requires a variable name");
+
+    /** @todo GNU make doesn't actually do the list thing for undefine, it seems
+     *        to assume everything after it is a single variable...  Going with
+     *        simple common code for now. */
+    return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_undefine, fQualifiers);
+}
+
+
+/**
+ * Parses a '[qualifiers] unexport variable [..]' expression.
+ *
+ * A 'unexport' directive is final, any qualifiers must preceed it.  So, we just
+ * have to extract the variable names now.
  *
  * @returns 1 to indicate we've handled a keyword (see
@@ -5391,4 +5449,37 @@
  * @param   fQualifiers The qualifiers.
  */
+static int kmk_cc_eval_do_var_unexport(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
+{
+    /*
+     * Join paths with undefine and export, unless it's an unexport all directive.
+     */
+    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
+    if (cchLeft)
+        return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_unexport, fQualifiers);
+
+    /*
+     * We're unexporting all variables.
+     */
+    PKMKCCEVALCORE pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
+    pInstr->enmOpcode = kKmkCcEvalInstr_unexport_all;
+    pInstr->iLine     = pCompiler->iLine;
+    return 1;
+}
+
+
+/**
+ * Parses a 'define variable' expression.
+ *
+ * A 'define' directive is final, any qualifiers must preceed it.  So, we just
+ * have to extract the variable name now, well and find the corresponding
+ * 'endef'.
+ *
+ * @returns 1 to indicate we've handled a keyword (see
+ *          kmk_cc_eval_try_handle_keyword).
+ * @param   pCompiler   The compiler state.
+ * @param   pchWord     First char after 'define'.
+ * @param   cchLeft     The number of chars left to parse on this line.
+ * @param   fQualifiers The qualifiers.
+ */
 static int kmk_cc_eval_do_var_define(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
 {
@@ -5400,6 +5491,6 @@
 
 
-static int kmk_cc_eval_handle_assignment_or_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchTmp,
-                                                   const char *pchWord, size_t cchLeft, unsigned fQualifiers)
+static int kmk_cc_eval_handle_assignment_or_recipe(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft,
+                                                   unsigned fQualifiers)
 {
     /*
@@ -5618,4 +5709,5 @@
         fPlainValue = memchr(pchWord, '$', cchLeft) == NULL;
 
+
         /*
          * Emit the instruction.
@@ -5657,5 +5749,6 @@
 
 /**
- * Parses a 'local [override] variable = value' expression.
+ * Parses a 'local [override] variable = value', 'local define variable', and
+ * 'local undefine variable [...]' expressions.
  *
  * The 'local' directive must be first and it does not permit any qualifiers at
@@ -5675,31 +5768,18 @@
     {
         /*
-         * Find the end of the variable name.
+         * Check for 'local define' and 'local undefine'
          */
-
-    }
-    else
-        kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name, assignment operator and value after 'local'");
-    return 1;
-}
-
-
-/**
- * Parses 'export [variable]' and 'export [qualifiers] variable = value'
- * expressions.
- *
- * When we find the 'export' directive at the start of a line, we need to
- * continue parsing with till we can tell the difference between the two forms.
- *
- * @returns 1 to indicate we've handled a keyword (see
- *          kmk_cc_eval_try_handle_keyword).
- * @param   pCompiler   The compiler state.
- * @param   pchWord     First char after 'define'.
- * @param   cchLeft     The number of chars left to parse on this line.
- * @param   fQualifiers The qualifiers.
- */
-static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft, unsigned fQualifiers)
-{
-    kmk_cc_eval_fatal(pCompiler, pchWord, "export not implemented yet");
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))   /* final */
+            return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft + 6, KMK_CC_EVAL_QUALIFIER_LOCAL);
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))   /* final */
+            return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft + 8, KMK_CC_EVAL_QUALIFIER_LOCAL);
+
+        /*
+         * Simpler to just join paths with the rest here, even if we could
+         * probably optimize the parsing a little if we liked.
+         */
+        return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_LOCAL);
+    }
+    kmk_cc_eval_fatal(pCompiler, pchWord, "Expected variable name, assignment operator and value after 'local'");
     return 1;
 }
@@ -5727,11 +5807,14 @@
             if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
             {
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))   /* final */
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))   /* final */
                     return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
 
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
-                    return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 6, cchLeft - 6, fQualifiers);
-
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8)) /* final */
+                    return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft -86, fQualifiers);
+
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8)) /* final */
+                    return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, fQualifiers);
+
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
                 {
                     if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_EXPORT))
@@ -5744,5 +5827,5 @@
                 }
 
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
                 {
                     if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_OVERRIDE))
@@ -5755,5 +5838,5 @@
                 }
 
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
                 {
                     if (!(fQualifiers & KMK_CC_EVAL_QUALIFIER_PRIVATE))
@@ -5775,5 +5858,5 @@
                 const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
                 if (pchEqual)
-                    return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchEqual, pchWord, cchLeft, fQualifiers);
+                    return kmk_cc_eval_handle_assignment_or_recipe(pCompiler, pchWord, cchLeft, fQualifiers);
             }
             return 0;
@@ -5787,4 +5870,117 @@
 
 /**
+ * Parses 'export [variable]' and 'export [qualifiers] variable = value'
+ * expressions.
+ *
+ * When we find the 'export' directive at the start of a line, we need to
+ * continue parsing with till we can tell the difference between the two forms.
+ *
+ * @returns 1 to indicate we've handled a keyword (see
+ *          kmk_cc_eval_try_handle_keyword).
+ * @param   pCompiler   The compiler state.
+ * @param   pchWord     First char after 'define'.
+ * @param   cchLeft     The number of chars left to parse on this line.
+ */
+static int kmk_cc_eval_handle_var_export(PKMKCCEVALCOMPILER pCompiler, const char *pchWord, size_t cchLeft)
+{
+    KMK_CC_EVAL_SKIP_SPACES_AFTER_WORD(pCompiler, pchWord, cchLeft);
+
+    if (cchLeft)
+    {
+        /*
+         * We need to figure out whether this is an assignment or a export statement,
+         * in the latter case join paths with 'export' and 'undefine'.
+         */
+        const char *pchEqual = (const char *)memchr(pchWord, '=', cchLeft);
+        if (!pchEqual)
+            return kmk_cc_eval_do_with_variable_list(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_export, 0 /*fQualifiers*/);
+
+        /*
+         * Found an '=', could be an assignment.  Let's take the easy way out
+         * and just parse the whole statement into words like we would do if
+         * it wasn't an assignment, and then check the words out for
+         * assignment keywords and operators.
+         */
+        unsigned iSavedEscEol = pCompiler->iEscEol;
+        unsigned cWords       = kmk_cc_eval_parse_words(pCompiler, pchWord, cchLeft);
+        if (cWords)
+        {
+            PKMKCCEVALWORD pWord = pCompiler->paWords;
+            unsigned       iWord = 0;
+            while (iWord < cWords)
+            {
+                /* Trailing assignment operator or terminal assignment directive ('undefine'
+                   and 'unexport' makes no sense here but GNU make ignores that). */
+                if (   (   pWord->cchWord > 1
+                        && pWord->pchWord[pWord->cchWord - 1] == '=')
+                    || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "define", 6)
+                    || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "undefine", 8)
+                    || KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "unexport", 8) )
+                {
+                    pCompiler->iEscEol = iSavedEscEol;
+                    return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft, KMK_CC_EVAL_QUALIFIER_EXPORT);
+                }
+
+                /* If not a variable assignment qualifier, it must be a variable name
+                   followed by an assignment operator. */
+                if (iWord + 1 < cWords)
+                {
+                    if (   !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "export", 6)
+                        && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "private", 7)
+                        && !KMK_CC_STRCMP_CONST(pWord->pchWord, pWord->cchWord, "override", 8))
+                    {
+                        pWord++;
+                        if (   pWord->cchWord > 0
+                            && (   pWord->pchWord[0] == '='
+                                || (   pWord->cchWord > 1
+                                    && pWord->pchWord[1] == '='
+                                    && (   pWord->pchWord[0] == ':'
+                                        || pWord->pchWord[0] == '+'
+                                        || pWord->pchWord[0] == '?'
+                                        || pWord->pchWord[0] == '<') ) ) )
+                        {
+                            pCompiler->iEscEol = iSavedEscEol;
+                            return kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord, cchLeft,
+                                                                            KMK_CC_EVAL_QUALIFIER_EXPORT);
+                        }
+                        break;
+                    }
+                }
+                else
+                    break;
+                /* next */
+                pWord++;
+                iWord++;
+            }
+
+            /*
+             * It's not an assignment.
+             * (This is the same as kmk_cc_eval_do_with_variable_list does.)
+             */
+            PKMKCCEVALVARIABLES pInstr = (PKMKCCEVALVARIABLES)kmk_cc_block_alloc_eval(pCompiler->ppBlockTail,
+                                                                                      KMKCCEVALVARIABLES_SIZE(cWords));
+            pInstr->Core.enmOpcode = kKmkCcEvalInstr_export;
+            pInstr->Core.iLine     = pCompiler->iLine;
+            pInstr->cVars          = cWords;
+            kmk_cc_eval_init_spp_array_from_duplicated_words(pCompiler, cWords, pCompiler->paWords, pInstr->aVars);
+            kmk_cc_block_realign(pCompiler->ppBlockTail);
+        }
+        else
+            KMK_CC_ASSERT(0);
+    }
+    else
+    {
+        /*
+         * We're exporting all variables.
+         */
+        PKMKCCEVALCORE pInstr = kmk_cc_block_alloc_eval(pCompiler->ppBlockTail, sizeof(*pInstr));
+        pInstr->enmOpcode = kKmkCcEvalInstr_export_all;
+        pInstr->iLine     = pCompiler->iLine;
+    }
+    return 1;
+}
+
+
+/**
  * When entering this function we know that the first two character in the first
  * word both independently occurs in keywords.
@@ -5811,13 +6007,15 @@
     if (KMK_CC_EVAL_IS_1ST_IN_VARIABLE_KEYWORD(ch))
     {
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5))
             return kmk_cc_eval_do_var_local(pCompiler, pchWord + 5, cchLeft - 5);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6))
             return kmk_cc_eval_do_var_define(pCompiler, pchWord + 6, cchLeft - 6, 0);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
-            return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6, 0);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6))
+            return kmk_cc_eval_handle_var_export(pCompiler, pchWord + 6, cchLeft - 6);
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8))
             return kmk_cc_eval_do_var_undefine(pCompiler, pchWord + 8, cchLeft - 8, 0);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8))
+            return kmk_cc_eval_do_var_unexport(pCompiler, pchWord + 8, cchLeft - 8, 0);
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8))
         {
             if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 8, cchLeft - 8, KMK_CC_EVAL_QUALIFIER_OVERRIDE))
@@ -5825,5 +6023,5 @@
             pCompiler->iEscEol = iSavedEscEol;
         }
-        else if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
+        else if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7))
         {
             if (kmk_cc_eval_try_handle_var_with_keywords(pCompiler, pchWord + 7, cchLeft - 7, KMK_CC_EVAL_QUALIFIER_PRIVATE))
@@ -5845,23 +6043,23 @@
         if (ch2 == 'f')
         {
-            if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
+            if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
                 return kmk_cc_eval_do_if(pCompiler, pchWord, cchLeft, 0 /* in else */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "eq", 2))
                 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 2, cchLeft - 2, 0 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "def", 3))
                 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "neq", 3))
                 return kmk_cc_eval_do_ifeq( pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 0 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "1of", 3))
                 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 3, cchLeft - 3, 0 /* in else */, 1 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "ndef", 4))
                 return kmk_cc_eval_do_ifdef(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
 
-            if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
+            if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "n1of", 4))
                 return kmk_cc_eval_do_if1of(pCompiler, pchWord + 4, cchLeft - 4, 0 /* in else */, 0 /* positive */);
         }
@@ -5871,5 +6069,5 @@
             pchWord += 5;
             cchLeft -= 5;
-            if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
+            if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
                 return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_include);
             if (cchLeft >= 3 && KMK_CC_WORD_COMP_CONST_3(pchWord, "dep"))
@@ -5877,9 +6075,9 @@
                 pchWord += 3;
                 cchLeft -= 3;
-                if (KMK_CC_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
+                if (KMK_CC_EVAL_WORD_COMP_IS_EOL(pCompiler, pchWord, cchLeft))
                     return kmk_cc_eval_do_include(pCompiler, pchWord, cchLeft, kKmkCcEvalInstr_includedep);
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6))
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-queue", 6))
                     return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_queue);
-                if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6))
+                if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-flush", 6))
                     return kmk_cc_eval_do_include(pCompiler, pchWord + 6, cchLeft - 6, kKmkCcEvalInstr_includedep_flush);
             }
@@ -5888,26 +6086,26 @@
     else if (ch == 'e') /* A few directives starts with 'e'. */
     {
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "else", 4))
             return kmk_cc_eval_do_else(pCompiler, pchWord + 4, cchLeft - 4);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "endif", 5))
             return kmk_cc_eval_do_endif(pCompiler, pchWord + 5, cchLeft - 5);
         /* export and endef are handled elsewhere, though stray endef's may end up here... */
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "export", 6));
 
     }
     else /* the rest. */
     {
-        if (   KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8)
-            || KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8))
+        if (   KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "sinclude", 8)
+            || KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "-include", 8))
             return kmk_cc_eval_do_include(pCompiler, pchWord + 8, cchLeft - 8, kKmkCcEvalInstr_include_silent);
-        if (KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5))
+        if (KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "vpath", 5))
             return kmk_cc_eval_do_vpath(pCompiler, pchWord + 5, cchLeft - 5);
 
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5));
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6));
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7));
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8));
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8));
-        KMK_CC_ASSERT(!KMK_CC_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "local", 5));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "define", 6));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "private", 7));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "override", 8));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "unexport", 8));
+        KMK_CC_ASSERT(!KMK_CC_EVAL_WORD_COMP_CONST(pCompiler, pchWord, cchLeft, "undefine", 8));
     }
 
@@ -6149,5 +6347,5 @@
                         pchTmp = (const char *)memchr(pchWord, '=', cchLeft);
                         if (pchTmp)
-                            kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchTmp, pchWord, cchLeft, 0);
+                            kmk_cc_eval_handle_assignment_or_recipe(&Compiler, pchWord, cchLeft, 0 /*fQualifiers*/);
                         else
                             kmk_cc_eval_handle_recipe(&Compiler, pchTmp, pchWord, cchLeft);
