From 6965abeefa29869541e1c071733bff213b9d65b4 Mon Sep 17 00:00:00 2001
From: Catherine <whitequark@whitequark.org>
Date: Sun, 23 Jul 2023 01:36:37 +0000
Subject: [PATCH] abc, abc9_exe: fix build on WASI (and others with `const*
 stdout`).

C does not guarantee that stdout/stderr can be reassigned.
Most platforms do make them assignable, however musl and WASI that
is based on musl do not. WASI does not have `dup2()`; instead it has
its own non-portable version of it that can only assign to previously
allocated fds.

Update the stream redirection code so that it does the right thing
on WASI and other platforms.
---
 passes/techmap/abc.cc      | 29 ++++++++++++++++++++++-------
 passes/techmap/abc9_exe.cc | 29 ++++++++++++++++++++++-------
 2 files changed, 44 insertions(+), 14 deletions(-)

diff --git a/passes/techmap/abc.cc b/passes/techmap/abc.cc
index 182e26c2f..364a8e544 100644
--- a/passes/techmap/abc.cc
+++ b/passes/techmap/abc.cc
@@ -1091,17 +1091,28 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 		buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
 		log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
 
-		abc_output_filter filt(tempdir_name, show_tempdir);
 #ifndef YOSYS_LINK_ABC
+		abc_output_filter filt(tempdir_name, show_tempdir);
 		int ret = run_command(buffer, std::bind(&abc_output_filter::next_line, filt, std::placeholders::_1));
 #else
 		string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str());
 		FILE *temp_stdouterr_w = fopen(temp_stdouterr_name.c_str(), "w");
 		if (temp_stdouterr_w == NULL)
 			log_error("ABC: cannot open a temporary file for output redirection");
-		FILE *old_stdout = stdout;
-		FILE *old_stderr = stderr;
-		stdout = stderr = temp_stdouterr_w;
+		fflush(stdout);
+		fflush(stderr);
+		FILE *old_stdout = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
+		FILE *old_stderr = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
+#if defined(__wasm)
+#define fd_renumber(from, to) (void)__wasi_fd_renumber(from, to)
+#else
+#define fd_renumber(from, to) dup2(from, to)
+#endif
+		fd_renumber(fileno(stdout), fileno(old_stdout));
+		fd_renumber(fileno(stderr), fileno(old_stderr));
+		fd_renumber(fileno(temp_stdouterr_w), fileno(stdout));
+		fd_renumber(fileno(temp_stdouterr_w), fileno(stderr));
+		fclose(temp_stdouterr_w);
 		// These needs to be mutable, supposedly due to getopt
 		char *abc_argv[5];
 		string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
@@ -1115,10 +1126,14 @@ void abc_module(RTLIL::Design *design, RTLIL::Module *current_module, std::strin
 		free(abc_argv[1]);
 		free(abc_argv[2]);
 		free(abc_argv[3]);
-		stdout = old_stdout;
-		stderr = old_stderr;
-		fclose(temp_stdouterr_w);
+		fflush(stdout);
+		fflush(stderr);
+		fd_renumber(fileno(old_stdout), fileno(stdout));
+		fd_renumber(fileno(old_stderr), fileno(stderr));
+		fclose(old_stdout);
+		fclose(old_stderr);
 		std::ifstream temp_stdouterr_r(temp_stdouterr_name);
+		abc_output_filter filt(tempdir_name, show_tempdir);
 		for (std::string line; std::getline(temp_stdouterr_r, line); )
 			filt.next_line(line + "\n");
 		temp_stdouterr_r.close();
diff --git a/passes/techmap/abc9_exe.cc b/passes/techmap/abc9_exe.cc
index 449b5b129..8e02e25a4 100644
--- a/passes/techmap/abc9_exe.cc
+++ b/passes/techmap/abc9_exe.cc
@@ -267,17 +267,28 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
 	buffer = stringf("\"%s\" -s -f %s/abc.script 2>&1", exe_file.c_str(), tempdir_name.c_str());
 	log("Running ABC command: %s\n", replace_tempdir(buffer, tempdir_name, show_tempdir).c_str());
 
-	abc9_output_filter filt(tempdir_name, show_tempdir);
 #ifndef YOSYS_LINK_ABC
+	abc9_output_filter filt(tempdir_name, show_tempdir);
 	int ret = run_command(buffer, std::bind(&abc9_output_filter::next_line, filt, std::placeholders::_1));
 #else
 	string temp_stdouterr_name = stringf("%s/stdouterr.txt", tempdir_name.c_str());
 	FILE *temp_stdouterr_w = fopen(temp_stdouterr_name.c_str(), "w");
 	if (temp_stdouterr_w == NULL)
 		log_error("ABC: cannot open a temporary file for output redirection");
-	FILE *old_stdout = stdout;
-	FILE *old_stderr = stderr;
-	stdout = stderr = temp_stdouterr_w;
+	fflush(stdout);
+	fflush(stderr);
+	FILE *old_stdout = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
+	FILE *old_stderr = fopen(temp_stdouterr_name.c_str(), "r"); // need any fd for renumbering
+#if defined(__wasm)
+#define fd_renumber(from, to) (void)__wasi_fd_renumber(from, to)
+#else
+#define fd_renumber(from, to) dup2(from, to)
+#endif
+	fd_renumber(fileno(stdout), fileno(old_stdout));
+	fd_renumber(fileno(stderr), fileno(old_stderr));
+	fd_renumber(fileno(temp_stdouterr_w), fileno(stdout));
+	fd_renumber(fileno(temp_stdouterr_w), fileno(stderr));
+	fclose(temp_stdouterr_w);
 	// These needs to be mutable, supposedly due to getopt
 	char *abc9_argv[5];
 	string tmp_script_name = stringf("%s/abc.script", tempdir_name.c_str());
@@ -291,10 +302,14 @@ void abc9_module(RTLIL::Design *design, std::string script_file, std::string exe
 	free(abc9_argv[1]);
 	free(abc9_argv[2]);
 	free(abc9_argv[3]);
-	stdout = old_stdout;
-	stderr = old_stderr;
-	fclose(temp_stdouterr_w);
+	fflush(stdout);
+	fflush(stderr);
+	fd_renumber(fileno(old_stdout), fileno(stdout));
+	fd_renumber(fileno(old_stderr), fileno(stderr));
+	fclose(old_stdout);
+	fclose(old_stderr);
 	std::ifstream temp_stdouterr_r(temp_stdouterr_name);
+	abc9_output_filter filt(tempdir_name, show_tempdir);
 	for (std::string line; std::getline(temp_stdouterr_r, line); )
 		filt.next_line(line + "\n");
 	temp_stdouterr_r.close();