Repository: riscv/sail-riscv
Pull request #762: Build most of the C simulator as C++
Author: login: arichardson
Labels: name: will be merged
description: Scheduled to be merged soon if nobody objects
Created: 2025-02-28T00:04:12Z | Merged: 2025-03-10T12:08:09Z

This will make it easier to add more features in the future.

While touching this code also fix various warnings.

History is intended to be clean, but happy to change this.


Diff:
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d2b6885601..37b7c2cbae 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -33,6 +33,11 @@ if (LINKER_SUPPORTS_NO_UNDEFINED)
     add_link_options("-Wl,--no-undefined")
 endif()
 
+add_compile_options(-Wall -Wextra -Wno-sign-compare)
+include(CheckCCompilerFlag)
+check_c_compiler_flag(-Wself-assign HAVE_WSELF_ASSIGN)
+check_c_compiler_flag(-Wimplicit-fallthrough HAVE_WIMPLICIT_FALLTHROUGH)
+
 # Extra CMake files.
 set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
 
@@ -46,6 +51,16 @@ if (STATIC)
         list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
     else()
         set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+        check_linker_flag(CXX "-static-libstdc++" HAVE_STATIC_LIBSTDCXX)
+        if (NOT HAVE_STATIC_LIBSTDCXX)
+            message(FATAL_ERROR "Building with -DSTATIC=TRUE requires static C++ std library installation")
+        endif()
+        add_link_options(-static-libstdc++)
+        check_linker_flag(CXX "-static-libgcc" HAVE_STATIC_LIBGCC)
+        if (NOT HAVE_STATIC_LIBGCC)
+            message(FATAL_ERROR "Building with -DSTATIC=TRUE requires static libgcc installation")
+        endif()
+        add_link_options(-static-libgcc)
     endif()
 endif()
 
@@ -71,6 +86,11 @@ if (DOWNLOAD_GMP)
         URL https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/gmp
         CONFIGURE_COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" --disable-shared --enable-static
+        # The libgmp.a output is created by the install step but since GMP::GMP
+        # depends on the entire ExternalProject build, we can pretend it is
+        # created by the build.
+        # TODO: Once we depend on CMake 3.26, use INSTALL_BYPRODUCTS
+        BUILD_BYPRODUCTS "<INSTALL_DIR>/lib/libgmp.a"
     )
     ExternalProject_Get_property(gmp INSTALL_DIR)
     add_library(GMP::GMP STATIC IMPORTED GLOBAL)
diff --git a/c_emulator/CMakeLists.txt b/c_emulator/CMakeLists.txt
index 718beb2dd6..635384445a 100644
--- a/c_emulator/CMakeLists.txt
+++ b/c_emulator/CMakeLists.txt
@@ -1,13 +1,13 @@
 set(EMULATOR_COMMON_SRCS
     riscv_config.h
-    riscv_platform.c
+    riscv_platform.cpp
     riscv_platform.h
-    riscv_platform_impl.c
+    riscv_platform_impl.cpp
     riscv_platform_impl.h
-    riscv_prelude.c
+    riscv_prelude.cpp
     riscv_prelude.h
     riscv_sail.h
-    riscv_sim.c
+    riscv_sim.cpp
     riscv_softfloat.c
     riscv_softfloat.h
 )
@@ -29,6 +29,17 @@ foreach (xlen IN ITEMS 32 64)
                 "${CMAKE_BINARY_DIR}/riscv_model_${arch}.c"
                 ${EMULATOR_COMMON_SRCS}
             )
+            # The generated model is not warnings-clean, silence them.
+            # -Wno-self-assing is needed for `zhtif_tohost = zhtif_tohost`
+            # generated by the sail code to avoid optimizing the function out.
+            set(_generated_c_warning_opt_out
+                -Wno-extra
+                -Wno-unused
+                -Wno-uninitialized
+                $<$<BOOL:${HAVE_WSELF_ASSIGN}>:-Wno-self-assign>
+            )
+            set_source_files_properties("${CMAKE_BINARY_DIR}/riscv_model_${arch}.c"
+                                        PROPERTIES COMPILE_OPTIONS "${_generated_c_warning_opt_out}")
 
             if (NOT arch IN_LIST DEFAULT_ARCHITECTURES)
                 set_target_properties(riscv_sim_${arch} PROPERTIES EXCLUDE_FROM_ALL TRUE)
diff --git a/c_emulator/riscv_platform.c b/c_emulator/riscv_platform.cpp
similarity index 65%
rename from c_emulator/riscv_platform.c
rename to c_emulator/riscv_platform.cpp
index e19008c510..af3e2f6185 100644
--- a/c_emulator/riscv_platform.c
+++ b/c_emulator/riscv_platform.cpp
@@ -1,6 +1,7 @@
 #include "sail.h"
 #include "rts.h"
 #include "riscv_prelude.h"
+#include "riscv_platform.h"
 #include "riscv_platform_impl.h"
 #include "riscv_sail.h"
 
@@ -17,148 +18,148 @@
 static mach_bits reservation = 0;
 static bool reservation_valid = false;
 
-bool sys_enable_rvc(unit u)
+bool sys_enable_rvc(unit)
 {
   return rv_enable_rvc;
 }
 
-bool sys_enable_fdext(unit u)
+bool sys_enable_fdext(unit)
 {
   return rv_enable_fdext;
 }
 
-bool sys_enable_svinval(unit u)
+bool sys_enable_svinval(unit)
 {
   return rv_enable_svinval;
 }
 
-bool sys_enable_zcb(unit u)
+bool sys_enable_zcb(unit)
 {
   return rv_enable_zcb;
 }
 
-bool sys_enable_zfinx(unit u)
+bool sys_enable_zfinx(unit)
 {
   return rv_enable_zfinx;
 }
 
-bool sys_enable_writable_fiom(unit u)
+bool sys_enable_writable_fiom(unit)
 {
   return rv_enable_writable_fiom;
 }
 
-bool sys_enable_vext(unit u)
+bool sys_enable_vext(unit)
 {
   return rv_enable_vext;
 }
 
-bool sys_enable_bext(unit u)
+bool sys_enable_bext(unit)
 {
   return rv_enable_bext;
 }
 
-bool sys_enable_zicbom(unit u)
+bool sys_enable_zicbom(unit)
 {
   return rv_enable_zicbom;
 }
 
-bool sys_enable_zicboz(unit u)
+bool sys_enable_zicboz(unit)
 {
   return rv_enable_zicboz;
 }
 
-bool sys_enable_sstc(unit u)
+bool sys_enable_sstc(unit)
 {
   return rv_enable_sstc;
 }
 
-uint64_t sys_pmp_count(unit u)
+uint64_t sys_pmp_count(unit)
 {
   return rv_pmp_count;
 }
 
-uint64_t sys_pmp_grain(unit u)
+uint64_t sys_pmp_grain(unit)
 {
   return rv_pmp_grain;
 }
 
-uint64_t sys_vector_vlen_exp(unit u)
+uint64_t sys_vector_vlen_exp(unit)
 {
   return rv_vector_vlen_exp;
 }
 
-uint64_t sys_vector_elen_exp(unit u)
+uint64_t sys_vector_elen_exp(unit)
 {
   return rv_vector_elen_exp;
 }
 
-bool sys_enable_writable_misa(unit u)
+bool sys_enable_writable_misa(unit)
 {
   return rv_enable_writable_misa;
 }
 
-mach_bits sys_writable_hpm_counters(unit u)
+mach_bits sys_writable_hpm_counters(unit)
 {
   return rv_writable_hpm_counters;
 }
 
-bool sys_vext_vl_use_ceil(unit u)
+bool sys_vext_vl_use_ceil(unit)
 {
   return rv_vext_vl_use_ceil;
 }
 
-bool plat_enable_dirty_update(unit u)
+bool plat_enable_dirty_update(unit)
 {
   return rv_enable_dirty_update;
 }
 
-bool plat_enable_misaligned_access(unit u)
+bool plat_enable_misaligned_access(unit)
 {
   return rv_enable_misaligned;
 }
 
-bool plat_mtval_has_illegal_inst_bits(unit u)
+bool plat_mtval_has_illegal_inst_bits(unit)
 {
   return rv_mtval_has_illegal_inst_bits;
 }
 
-mach_bits plat_ram_base(unit u)
+mach_bits plat_ram_base(unit)
 {
   return rv_ram_base;
 }
 
-mach_bits plat_ram_size(unit u)
+mach_bits plat_ram_size(unit)
 {
   return rv_ram_size;
 }
 
-mach_bits plat_rom_base(unit u)
+mach_bits plat_rom_base(unit)
 {
   return rv_rom_base;
 }
 
-mach_bits plat_rom_size(unit u)
+mach_bits plat_rom_size(unit)
 {
   return rv_rom_size;
 }
 
-mach_bits plat_cache_block_size_exp()
+mach_bits plat_cache_block_size_exp(unit)
 {
   return rv_cache_block_size_exp;
 }
 
 // Provides entropy for the scalar cryptography extension.
-mach_bits plat_get_16_random_bits(unit u)
+mach_bits plat_get_16_random_bits(unit)
 {
   return rv_16_random_bits();
 }
 
-mach_bits plat_clint_base(unit u)
+mach_bits plat_clint_base(unit)
 {
   return rv_clint_base;
 }
 
-mach_bits plat_clint_size(unit u)
+mach_bits plat_clint_size(unit)
 {
   return rv_clint_size;
 }
@@ -171,12 +172,12 @@ unit load_reservation(mach_bits addr)
   return UNIT;
 }
 
-bool speculate_conditional(unit u)
+bool speculate_conditional(unit)
 {
   return true;
 }
 
-static mach_bits check_mask(void)
+static mach_bits check_mask()
 {
   return (zxlen_val == 32) ? 0x00000000FFFFFFFF : -1;
 }
@@ -191,7 +192,7 @@ bool match_reservation(mach_bits addr)
   return ret;
 }
 
-unit cancel_reservation(unit u)
+unit cancel_reservation(unit)
 {
   RESERVATION_DBG("reservation <- none\n");
   reservation_valid = false;
@@ -205,14 +206,14 @@ unit plat_term_write(mach_bits s)
   return UNIT;
 }
 
-void plat_insns_per_tick(sail_int *rop, unit u) { }
+void plat_insns_per_tick(sail_int *, unit) { }
 
-mach_bits plat_htif_tohost(unit u)
+mach_bits plat_htif_tohost(unit)
 {
   return rv_htif_tohost;
 }
 
-unit memea(mach_bits len, sail_int n)
+unit memea(mach_bits, sail_int)
 {
   return UNIT;
 }
diff --git a/c_emulator/riscv_platform.h b/c_emulator/riscv_platform.h
index 8d8d8aaef4..6db13e224a 100644
--- a/c_emulator/riscv_platform.h
+++ b/c_emulator/riscv_platform.h
@@ -1,6 +1,10 @@
 #pragma once
 #include "sail.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 bool sys_enable_rvc(unit);
 bool sys_enable_fdext(unit);
 bool sys_enable_svinval(unit);
@@ -24,7 +28,7 @@ uint64_t sys_vector_elen_exp(unit);
 bool plat_enable_dirty_update(unit);
 bool plat_enable_misaligned_access(unit);
 bool plat_mtval_has_illegal_inst_bits(unit);
-mach_bits sys_writable_hpm_counters(unit u);
+mach_bits sys_writable_hpm_counters(unit);
 
 mach_bits plat_ram_base(unit);
 mach_bits plat_ram_size(unit);
@@ -52,3 +56,7 @@ unit plat_term_write(mach_bits);
 mach_bits plat_htif_tohost(unit);
 
 unit memea(mach_bits, sail_int);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/c_emulator/riscv_platform_impl.c b/c_emulator/riscv_platform_impl.cpp
similarity index 100%
rename from c_emulator/riscv_platform_impl.c
rename to c_emulator/riscv_platform_impl.cpp
diff --git a/c_emulator/riscv_prelude.c b/c_emulator/riscv_prelude.cpp
similarity index 84%
rename from c_emulator/riscv_prelude.c
rename to c_emulator/riscv_prelude.cpp
index b43421f5f2..4cb7390265 100644
--- a/c_emulator/riscv_prelude.c
+++ b/c_emulator/riscv_prelude.cpp
@@ -15,7 +15,7 @@ unit print_instr(sail_string s)
   return UNIT;
 }
 
-unit print_step(unit u)
+unit print_step(unit)
 {
   if (config_print_step)
     fprintf(trace_log, "\n");
@@ -43,22 +43,22 @@ unit print_platform(sail_string s)
   return UNIT;
 }
 
-bool get_config_print_instr(unit u)
+bool get_config_print_instr(unit)
 {
   return (config_print_instr) ? true : false;
 }
 
-bool get_config_print_reg(unit u)
+bool get_config_print_reg(unit)
 {
   return (config_print_reg) ? true : false;
 }
 
-bool get_config_print_mem(unit u)
+bool get_config_print_mem(unit)
 {
   return (config_print_mem_access) ? true : false;
 }
 
-bool get_config_print_platform(unit u)
+bool get_config_print_platform(unit)
 {
   return (config_print_platform) ? true : false;
 }
diff --git a/c_emulator/riscv_prelude.h b/c_emulator/riscv_prelude.h
index f6692b414f..91fe22e89f 100644
--- a/c_emulator/riscv_prelude.h
+++ b/c_emulator/riscv_prelude.h
@@ -3,15 +3,23 @@
 #include "rts.h"
 #include "riscv_softfloat.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 unit print_string(sail_string prefix, sail_string msg);
 
 unit print_instr(sail_string s);
-unit print_step(unit u);
+unit print_step(unit);
 unit print_reg(sail_string s);
 unit print_mem_access(sail_string s);
 unit print_platform(sail_string s);
 
-bool get_config_print_instr(unit u);
-bool get_config_print_reg(unit u);
-bool get_config_print_mem(unit u);
-bool get_config_print_platform(unit u);
+bool get_config_print_instr(unit);
+bool get_config_print_reg(unit);
+bool get_config_print_mem(unit);
+bool get_config_print_platform(unit);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/c_emulator/riscv_sail.h b/c_emulator/riscv_sail.h
index da5aa94458..67e0ad759f 100644
--- a/c_emulator/riscv_sail.h
+++ b/c_emulator/riscv_sail.h
@@ -2,6 +2,10 @@
    Ideally, this would be autogenerated.
  */
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 typedef int unit;
 #define UNIT 0
 typedef uint64_t mach_bits;
@@ -32,7 +36,6 @@ extern bool zrvfi_int_data_present;
 void zrvfi_get_int_data(sail_bits *rop, unit);
 extern bool zrvfi_mem_data_present;
 void zrvfi_get_mem_data(sail_bits *rop, unit);
-mach_bits zrvfi_get_v2_trace_sizze(unit);
 void zrvfi_get_v2_support_packet(sail_bits *rop, unit);
 
 // Debugging prints
@@ -67,3 +70,7 @@ struct zMcause {
 extern struct zMcause zmcause, zscause;
 
 extern mach_bits zminstret;
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
diff --git a/c_emulator/riscv_sim.c b/c_emulator/riscv_sim.cpp
similarity index 97%
rename from c_emulator/riscv_sim.c
rename to c_emulator/riscv_sim.cpp
index e2cc2a6d19..f5576cba3d 100644
--- a/c_emulator/riscv_sim.c
+++ b/c_emulator/riscv_sim.cpp
@@ -412,7 +412,7 @@ static int process_args(int argc, char **argv)
     case OPT_CACHE_BLOCK_SIZE:
       block_size_exp = ilog2(atol(optarg));
 
-      if (block_size_exp < 0 || block_size_exp > 12) {
+      if (block_size_exp > 12) {
         fprintf(stderr, "invalid cache-block-size '%s' provided.\n", optarg);
         exit(1);
       }
@@ -521,7 +521,7 @@ void init_sail_reset_vector(uint64_t entry)
 
   rv_rom_base = DEFAULT_RSTVEC;
   uint64_t addr = rv_rom_base;
-  for (int i = 0; i < sizeof(reset_vec); i++)
+  for (size_t i = 0; i < sizeof(reset_vec); i++)
     write_mem(addr++, (uint64_t)((char *)reset_vec)[i]);
 
   if (dtb && dtb_len) {
@@ -532,7 +532,7 @@ void init_sail_reset_vector(uint64_t entry)
   /* zero-fill to page boundary */
   const int align = 0x1000;
   uint64_t rom_end = (addr + align - 1) / align * align;
-  for (int i = addr; i < rom_end; i++)
+  for (uint64_t i = addr; i < rom_end; i++)
     write_mem(addr++, 0);
 
   /* set rom size */
@@ -685,7 +685,6 @@ void rvfi_send_trace(unsigned version)
   if (version == 1) {
     get_and_send_rvfi_packet(zrvfi_get_exec_packet_v1);
   } else if (version == 2) {
-    mach_bits trace_size = zrvfi_get_v2_trace_sizze(UNIT);
     get_and_send_rvfi_packet(zrvfi_get_exec_packet_v2);
     if (zrvfi_int_data_present)
       get_and_send_rvfi_packet(zrvfi_get_int_data);
@@ -707,9 +706,6 @@ void run_sail(void)
   /* initialize the step number */
   mach_int step_no = 0;
   int insn_cnt = 0;
-#ifdef RVFI_DII
-  bool need_instr = true;
-#endif
 
   struct timeval interval_start;
   if (gettimeofday(&interval_start, NULL) < 0) {
@@ -788,12 +784,15 @@ void run_sail(void)
                   (intmax_t)insn);
           exit(1);
         }
-        rvfi_trace_version
-            = insn; // From now on send traces in the requested format
+        // From now on send traces in the requested format
+        rvfi_trace_version = insn;
         struct {
           char msg[8];
           uint64_t version;
-        } version_response = {"version=", rvfi_trace_version};
+        } version_response = {
+            {'v', 'e', 'r', 's', 'i', 'o', 'n', '='},
+            rvfi_trace_version
+        };
         if (write(rvfi_dii_sock, &version_response, sizeof(version_response))
             != sizeof(version_response)) {
           fprintf(stderr, "Sending version response failed: %s\n",
@@ -890,7 +889,7 @@ void init_logs()
 
   if (trace_log_path == NULL) {
     trace_log = stdout;
-  } else if ((trace_log = fopen(trace_log_path, "w+")) < 0) {
+  } else if ((trace_log = fopen(trace_log_path, "w+")) == NULL) {
     fprintf(stderr, "Cannot create trace log '%s': %s\n", trace_log_path,
             strerror(errno));
     exit(1);
@@ -933,9 +932,10 @@ int main(int argc, char **argv)
               strerror(errno));
       return 1;
     }
-    struct sockaddr_in addr = {.sin_family = AF_INET,
-                               .sin_addr.s_addr = htonl(INADDR_LOOPBACK),
-                               .sin_port = htons(rvfi_dii_port)};
+    struct sockaddr_in addr;
+    addr.sin_family = AF_INET;
+    addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+    addr.sin_port = htons(rvfi_dii_port);
     if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) {
       fprintf(stderr, "Unable to set bind socket: %s\n", strerror(errno));
       return 1;
diff --git a/dependencies/softfloat/CMakeLists.txt b/dependencies/softfloat/CMakeLists.txt
index 6650170093..0ecbfbd7e7 100644
--- a/dependencies/softfloat/CMakeLists.txt
+++ b/dependencies/softfloat/CMakeLists.txt
@@ -41,4 +41,10 @@ target_include_directories(softfloat PUBLIC
     "${source_dir}/build/Linux-RISCV-GCC"
 )
 
-target_compile_options(softfloat PRIVATE "-Werror=implicit-function-declaration" "-DSOFTFLOAT_ROUND_ODD")
+target_compile_options(softfloat PRIVATE
+        -Werror=implicit-function-declaration
+        -Wno-unused-parameter
+        -Wno-unused-variable
+        $<$<BOOL:${HAVE_WIMPLICIT_FALLTHROUGH}>:-Wno-implicit-fallthrough>
+)
+target_compile_definitions(softfloat PRIVATE SOFTFLOAT_ROUND_ODD)
diff --git a/sail_runtime/CMakeLists.txt b/sail_runtime/CMakeLists.txt
index d92f354cac..4681aa8253 100644
--- a/sail_runtime/CMakeLists.txt
+++ b/sail_runtime/CMakeLists.txt
@@ -21,6 +21,7 @@ add_library(sail_runtime
 target_include_directories(sail_runtime
     PUBLIC "${sail_dir}/lib"
 )
+target_compile_options(sail_runtime PRIVATE -Wno-extra -Wno-unused)
 
 if (COVERAGE)
     find_package(Threads REQUIRED)


Reviews:
user: login: arichardson
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T01:24:13Z
user: login: Timmmm
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T09:30:29Z
user: login: Timmmm
body: This is great.
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-02-28T09:31:20Z
user: login: arichardson
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T17:16:25Z
user: login: Timmmm
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-02-28T20:25:44Z
user: login: Timmmm
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T22:19:41Z
user: login: Timmmm
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T22:20:22Z
user: login: arichardson
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-03T22:54:16Z
user: login: Timmmm
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-04T09:39:35Z
user: login: jordancarlin
body: LGTM
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-04T22:59:27Z

Review comments:
diff_hunk: @@ -71,6 +76,11 @@ if (DOWNLOAD_GMP)
         URL https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/gmp
         CONFIGURE_COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" --disable-shared --enable-static
+        # The libgmp.a output is created by the install step but since GMP::GMP
+        # depends on the entire ExternalProject build, we can pretend it is
+        # created by the build.
+        # TODO: Once we depend on CMake 3.26, use INSTALL_BYPRODUCTS
+        BUILD_BYPRODUCTS "<INSTALL_DIR>/lib/libgmp.a"
path: CMakeLists.txt
user: login: arichardson
body: This change is unrelated and I can pull it into a separate commit. Just noticed it while building with many jobs.
created_at: 2025-02-28T01:24:13Z
author_association: COLLABORATOR
diff_hunk: @@ -71,6 +76,11 @@ if (DOWNLOAD_GMP)
         URL https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/gmp
         CONFIGURE_COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" --disable-shared --enable-static
+        # The libgmp.a output is created by the install step but since GMP::GMP
+        # depends on the entire ExternalProject build, we can pretend it is
+        # created by the build.
+        # TODO: Once we depend on CMake 3.26, use INSTALL_BYPRODUCTS
+        BUILD_BYPRODUCTS "<INSTALL_DIR>/lib/libgmp.a"
path: CMakeLists.txt
user: login: Timmmm
body: Does something break if you don't have this then?
created_at: 2025-02-28T09:30:29Z
author_association: COLLABORATOR
diff_hunk: @@ -71,6 +76,11 @@ if (DOWNLOAD_GMP)
         URL https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/gmp
         CONFIGURE_COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" --disable-shared --enable-static
+        # The libgmp.a output is created by the install step but since GMP::GMP
+        # depends on the entire ExternalProject build, we can pretend it is
+        # created by the build.
+        # TODO: Once we depend on CMake 3.26, use INSTALL_BYPRODUCTS
+        BUILD_BYPRODUCTS "<INSTALL_DIR>/lib/libgmp.a"
path: CMakeLists.txt
user: login: arichardson
body: I got a build failure with DOWNLOAD_GMP and `ninja -j 64`. Should I submit it as a separate PR?
created_at: 2025-02-28T17:16:25Z
author_association: COLLABORATOR
diff_hunk: @@ -71,6 +76,11 @@ if (DOWNLOAD_GMP)
         URL https://gmplib.org/download/gmp/gmp-6.3.0.tar.xz
         INSTALL_DIR ${CMAKE_CURRENT_BINARY_DIR}/gmp
         CONFIGURE_COMMAND "<SOURCE_DIR>/configure" "--prefix=<INSTALL_DIR>" --disable-shared --enable-static
+        # The libgmp.a output is created by the install step but since GMP::GMP
+        # depends on the entire ExternalProject build, we can pretend it is
+        # created by the build.
+        # TODO: Once we depend on CMake 3.26, use INSTALL_BYPRODUCTS
+        BUILD_BYPRODUCTS "<INSTALL_DIR>/lib/libgmp.a"
path: CMakeLists.txt
user: login: Timmmm
body: Nah I was just trying to understand it. I still don't understand why it fails without this though. The docs just say:

> Files that will be generated by the build command but may or may not have their modification time updated by subsequent builds.
created_at: 2025-02-28T20:25:44Z
author_association: COLLABORATOR
diff_hunk: @@ -46,6 +51,16 @@ if (STATIC)
         list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
     else()
         set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+        check_linker_flag(CXX "-static-libstdc++" HAVE_STATIC_LIBSTDCXX)
+        if (NOT HAVE_STATIC_LIBSTDCXX)
+            message(FATAL_ERROR "Building with -DSTATIC+TRUE requires static C++ std library installation")
path: CMakeLists.txt
user: login: Timmmm
body: ```suggestion
            message(FATAL_ERROR "Building with -DSTATIC=TRUE requires static C++ std library installation")
```

Presumably?
created_at: 2025-03-03T22:19:41Z
author_association: COLLABORATOR
diff_hunk: @@ -46,6 +51,16 @@ if (STATIC)
         list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
     else()
         set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+        check_linker_flag(CXX "-static-libstdc++" HAVE_STATIC_LIBSTDCXX)
+        if (NOT HAVE_STATIC_LIBSTDCXX)
+            message(FATAL_ERROR "Building with -DSTATIC+TRUE requires static C++ std library installation")
+        endif()
+        add_link_options(-static-libstdc++)
+        check_linker_flag(CXX "-static-libgcc" HAVE_STATIC_LIBGCC)
+        if (NOT HAVE_STATIC_LIBGCC)
+            message(FATAL_ERROR "Building with -DSTATIC+TRUE requires static libgcc installation")
path: CMakeLists.txt
user: login: Timmmm
body: Ditto? Or is this some sorted syntax I've never seen?
created_at: 2025-03-03T22:20:22Z
author_association: COLLABORATOR
diff_hunk: @@ -46,6 +51,16 @@ if (STATIC)
         list(INSERT CMAKE_FIND_LIBRARY_SUFFIXES 0 .lib .a)
     else()
         set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
+        check_linker_flag(CXX "-static-libstdc++" HAVE_STATIC_LIBSTDCXX)
+        if (NOT HAVE_STATIC_LIBSTDCXX)
+            message(FATAL_ERROR "Building with -DSTATIC+TRUE requires static C++ std library installation")
path: CMakeLists.txt
user: login: arichardson
body: Ah yes, fixed now.
created_at: 2025-03-03T22:54:16Z
author_association: COLLABORATOR

PR comments:
user: login: github-actions[bot]
created_at: 2025-02-28T00:24:39Z
body: ## Test Results
396 tests  ±0   396 ✅ ±0   1m 19s ⏱️ ±0s
  1 suites ±0     0 💤 ±0 
  1 files   ±0     0 ❌ ±0 

Results for commit 2a95e162. ± Comparison against base commit 40d26b58.

[test-results]:data:application/gzip;base64,H4sIAM08y2cC/13MSw7CIBSF4a00jB3QSwFxM4ZncmNbDIVR496lVftw+P0nOTMJ2PuJ3Jr20pCpYN7gStIZ41gpVXVd8rIxJX66T8Xa//TAZ010C0Fjfwo+pZi+JZVx/1xwvvyU/XH14XD18c/GYcBcQUAr7lsB0DHGJIADzzmnXlHBDXNGdlcZAjXk9Qbg1jefBAEAAA==

:recycle: This comment has been updated with latest results.
author_association: NONE
user: login: Timmmm
created_at: 2025-03-03T16:29:21Z
body: If you build with the `-DSTATIC=TRUE` presumably it doesn't statically link with libstdc++? Do we want to statically link it? 
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-03T16:55:56Z
body: Hmm we could use -nostdlib++ for now since we don't use any library features yet? Or alternatively -static-libstdc++. Let me make this change
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-03T17:20:59Z
body: Yeah I think let's not use `-nostdlib++` since we definitely are going to want to use standard library features. `-static-libstdc++` seems reasonable. My brief googling suggests the main caveats with it are around `dlopen` which we don't use.
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-03T18:17:10Z
body: Updated to use -static-libstdc++
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-03T18:22:21Z
body: Do we also need static unwind lib? -static-libgcc?
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-03T18:29:31Z
body: > Do we also need static unwind lib? -static-libgcc?

Added now so it's back to 
```
ldd cmake-build-release/c_emulator/riscv_sim_rv64d
        linux-vdso.so.1 (0x00007f834fe91000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f834f80a000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f834fe93000)
```
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-03T21:43:43Z
body: Nice. Is the binary still a reasonable size?
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-03T22:02:55Z
body: > Nice. Is the binary still a reasonable size?

```
❯ size cmake-build-release/c_emulator/riscv_sim_rv64d
   text    data     bss     dec     hex filename
3103448   32328   77720 3213496  3108b8 cmake-build-release/c_emulator/riscv_sim_rv64d
❯ size cmake-build-release/c_emulator/riscv_sim_rv64d
   text    data     bss     dec     hex filename
3103084   32328   77752 3213164  31076c cmake-build-release/c_emulator/riscv_sim_rv64d
```

Adding a basic use of iostream only seems to add 300 bytes of text (maybe it's converted to fprintf). We will only pay for code size for the C++ features that we use in the future.
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-04T09:40:11Z
body: LGTM, there was support for this in the meeting so I'll add the 'will be merged' tag but I'll give it a week or so since it's a significant change.
author_association: COLLABORATOR
user: login: arichardson
created_at: 2025-03-07T18:30:22Z
body: rebased to fix conflict.
author_association: COLLABORATOR
user: login: Alasdair
created_at: 2025-03-10T15:56:29Z
body: After this change I get `fatal error: bracket nesting level exceeded maximum of 256`
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-10T16:04:02Z
body: Google says maybe `-fbracket-depth=1024` will help, but it's weird that just this change triggered it. What compiler are you using?
author_association: COLLABORATOR
user: login: Alasdair
created_at: 2025-03-10T16:04:50Z
body: Apple clang
author_association: COLLABORATOR
user: login: jordancarlin
created_at: 2025-03-10T16:23:52Z
body: Looks like gcc supports up to 1024 with no option to change it but clang defaults to 256 and has a flag to increase it. We should probably add a check to the CMake file that adds this option if it detects that it’s running with clang.

Might be worth compiling the model with both GCC and clang in CI to catch these sorts of things. 
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-10T16:25:37Z
body: Oh I'm getting it too now with Clang (but not GCC). I think it's actually because of #617, but yeah let's add a flag.

Also, it occurs to me that we didn't actually check how compile time and performance were affected by #617 - it could potentially be significant I guess.
author_association: COLLABORATOR
user: login: Timmmm
created_at: 2025-03-10T16:39:21Z
body: #780  - I'm just checking the compile time too...
author_association: COLLABORATOR
user: login: Alasdair
created_at: 2025-03-10T16:42:24Z
body: I can do something like:
```
      let cdefs = List.map (Jib_optimize.flatten_cdef ~max_depth:100) cdefs in
```
to flatten any deeply nested C definitions in Sail during code generation.
author_association: COLLABORATOR
user: login: Alasdair
created_at: 2025-03-10T16:52:54Z
body: It might also be the `newtype regidx` change that triggers it in addition to this, as Sail generates lots of extra code that just wraps and unwraps the type. I'll add the optimisation to make the `newtype` wrappers transparent.
author_association: COLLABORATOR