Repository: pyodide/pyodide

Issue:
"ERROR: build script failed" but "Succeeded building package"
## 🐛 Bug

<!-- A clear and concise description of what the bug is. -->
`pyodide build-recipes libgmp --install` fails (but that's a separate issue).
It correctly shows "ERROR: build script failed".
But then it proceeds with "Succeeded building package libgmp".

```
mpn/sec_pi1_div_r.o mpn/sec_add_1.o mpn/sec_sub_1.o mpn/sec_invert.o mpn/trialdiv.o .libs/libgmp.lax/lt105-remove.o mpn/and_n.o
mpn/andn_n.o mpn/nand_n.o mpn/ior_n.o mpn/iorn_n.o mpn/nior_n.o mpn/xor_n.o mpn/xnor_n.o mpn/copyi.o mpn/copyd.o mpn/zero.o    
mpn/sec_tabselect.o mpn/comb_tables.o mpn/add_n_sub_n.o printf/asprintf.o printf/asprntffuns.o printf/doprnt.o printf/doprntf.o
printf/doprnti.o printf/fprintf.o printf/obprintf.o printf/obvprintf.o printf/obprntffuns.o printf/printf.o printf/printffuns.o
printf/snprintf.o printf/snprntffuns.o printf/sprintf.o printf/sprintffuns.o printf/vasprintf.o printf/vfprintf.o              
printf/vprintf.o printf/vsnprintf.o printf/vsprintf.o printf/repl-vsnprintf.o scanf/doscan.o scanf/fscanf.o scanf/fscanffuns.o 
scanf/scanf.o scanf/sscanf.o scanf/sscanffuns.o scanf/vfscanf.o scanf/vscanf.o scanf/vsscanf.o rand/rand.o rand/randclr.o      
rand/randdef.o rand/randiset.o rand/randlc2s.o rand/randlc2x.o rand/randmt.o rand/randmts.o rand/rands.o rand/randsd.o         
rand/randsdui.o rand/randbui.o rand/randmui.o                                                                                  
/workspaces/pyodide/emsdk/emsdk/upstream/bin/llvm-ar: error: .libs/libgmp.lax/lt1-abs.o: No such file or directory             
make[2]: *** [Makefile:882: libgmp.la] Error 1                                                                                 
make[2]: Leaving directory '/workspaces/pyodide/packages/libgmp/build/libgmp-6.2.1'                                            
make[1]: *** [Makefile:997: all-recursive] Error 1                                                                             
make[1]: Leaving directory '/workspaces/pyodide/packages/libgmp/build/libgmp-6.2.1'                                            
make: *** [Makefile:787: all] Error 2                                                                                          
emmake: error: 'make -j 1' failed (returned 2)                                                                                 
ERROR: build script failed                                                                                                     
    emconfigure ./configure \                                                                                                  
        CFLAGS="-fPIC" \                                                                                                       
        --disable-dependency-tracking \                                                                                        
        --host none \                                                                                                          
        --disable-shared \                                                                                                     
        --enable-static \                                                                                                      
        --prefix=${WASM_LIBRARY_DIR}                                                                                           
    emmake make -j ${PYODIDE_JOBS:-3}                                                                                          
    emmake make install                                                                                                        
                                                                                                                               
[2024-01-21 19:00:26] Succeeded building package libgmp in 251.0 seconds.                                                      
```

### To Reproduce

<!-- Minimal code example to reproduce the bug. -->
In the Conda devcontainer configured in #4402, type
`pyodide build-recipes libgmp --install`.

### Expected behavior

<!-- FILL IN -->
Either build without error, or report an error.

### Environment

- Pyodide Version<!-- (e.g. 1.8.1) -->: 0.26.0.dev0
- Browser version<!-- (e.g. Chrome 95.0.4638.54) -->: N/A

<!-- If you are building Pyodide by yourself, please also include these information: -->

- Commit hash of Pyodide git repository: 09f5f5493ef0e0db142d11d6a9df8accb645d59f
- Build environment: Conda devcontainer configured in #4402, running on macOS

### Additional context

<!-- Add any other context about the problem here. -->



Discussion:
Thanks for the report. I think this bug has been present for the full three years I've been a maintainer of Pyodide and nobody has ever gotten around to fixing it... It is a bit confusing though.
Any hint where to start to look to fix it?
Looks to me that the problem is here:
https://github.com/pyodide/pyodide/blob/main/pyodide-build/pyodide_build/buildpkg.py?plain=1#L863-L873
```py
    success = True
    try:
        _build_package_inner(...)
    except Exception:
        success = False
        raise
    finally:
        status = "Succeeded" if success else "Failed"
```
`success` is being left as `True` so the generic exception handler is not being executed. The ERROR message is printed here:
https://github.com/pyodide/pyodide/blob/main/pyodide-build/pyodide_build/buildpkg.py?plain=1#L124-L126
```py
            logger.error(f"ERROR: {script_name} failed")
            logger.error(textwrap.indent(cmd, "    "))
            exit_with_stdio(result)
```
And `exit_with_stdio` raises `SystemExit` which is not caught by `except Exception`. So we should add handling for `KeyboardInterrupt` and `SystemExit` on line 863. I think the following patch would probably be sufficient:
```patch
--- a/pyodide-build/pyodide_build/buildpkg.py
+++ b/pyodide-build/pyodide_build/buildpkg.py
@@ -860,9 +860,11 @@ def build_package(
             continue_=continue_,
         )
 
-    except Exception:
+    except (Exception, KeyboardInterrupt):
         success = False
         raise
+    except SystemExit as e:
+        success = e.code == 0
     finally:
         t1 = datetime.now()
         datestamp = "[{}]".format(t1.strftime("%Y-%m-%d %H:%M:%S"))
```
Though we might consider adding a distinct message for `KeyboardInterrupt` and I'm not sure that anyone ever raises `SystemExit(0)` so it's not clear how important that case is.
I think it needs to re-raise in the `SystemExit` case too

Resolving patch:
diff --git a/pyodide-build/pyodide_build/buildpkg.py b/pyodide-build/pyodide_build/buildpkg.py
--- a/pyodide-build/pyodide_build/buildpkg.py
+++ b/pyodide-build/pyodide_build/buildpkg.py
@@ -860,9 +860,12 @@ def build_package(
             continue_=continue_,
         )
 
-    except Exception:
+    except (Exception, KeyboardInterrupt):
         success = False
         raise
+    except SystemExit as e:
+        success = e.code == 0
+        raise
     finally:
         t1 = datetime.now()
         datestamp = "[{}]".format(t1.strftime("%Y-%m-%d %H:%M:%S"))


Test patch: