After installing all the required deps and you run make qemu
, you will face this error:
user/sh.c: In function 'runcmd':
user/sh.c:60:1: error: infinite recursion detected [-Werror=infinite-recursion]
60 | runcmd(struct cmd *cmd)
| ^~~~~~
user/sh.c:91:5: note: recursive call
91 | runcmd(rcmd->cmd);
| ^~~~~~~~~~~~~~~~~
user/sh.c:111:7: note: recursive call
111 | runcmd(pcmd->left);
| ^~~~~~~~~~~~~~~~~~
user/sh.c:118:7: note: recursive call
118 | runcmd(pcmd->right);
| ^~~~~~~~~~~~~~~~~~~
user/sh.c:97:7: note: recursive call
97 | runcmd(lcmd->left);
| ^~~~~~~~~~~~~~~~~~
user/sh.c:99:5: note: recursive call
99 | runcmd(lcmd->right);
| ^~~~~~~~~~~~~~~~~~~
user/sh.c:129:7: note: recursive call
129 | runcmd(bcmd->cmd);
| ^~~~~~~~~~~~~~~~~
cc1: all warnings being treated as errors
make: *** [user/sh.o] Error 1
This is because in the Makefile
CFLAGS
, we have the -Werror
flag (line 70) which tells the compiler (gcc/clang) to treat all warnings as errors.
This means any warnigs that would normally just display a message will instead cause the compilation to fail.
-
Go to the file
user/sh.c
and find the functionruncmd(struct cmd *cmd)
-
Make the following file changes to it:
diff --git a/user/sh.c b/user/sh.c
index 83dd513..7f93bb2 100644
--- a/user/sh.c
+++ b/user/sh.c
// Execute cmd. Never returns.
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winfinite-recursion"
void
runcmd(struct cmd *cmd)
{
@@ -129,6 +131,7 @@ runcmd(struct cmd *cmd)
}
exit(0);
}
+#pragma GCC diagnostic pop
The key changes are:
- Added
#pragma GCC diagnostic push
to save the current warning settings - Added
#pragma GCC diagnostic ignored "-Winfinite-recursion"
to disable the specific warning - Added
#pragma GCC diagnostic pop
to restore the warning settings after the function
This is safe because:
-
Each recursive call is always in a different process (after fork)
-
The recursion will terminate when we hit an EXEC command
-
The shell command structure is inherently recursive (commands can contain other commands)
-
Each path either:
- Calls
exec()
which replaces the current process - Or exits explicitly
- Or makes a recursive call in a child process
- Calls
The pragmas tell the compiler that we understand there's recursion here and it's intentional. This resolves the compilation error while maintaining the correct shell behavior.