diff --git a/.gitignore b/.gitignore index 3505209..33b0bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ /ocaml-*.tar.gz /ocaml-*.tar.xz /ocaml-*-refman.pdf +/4.11.0.tar.gz +/4.13.1.tar.gz diff --git a/0001-Don-t-add-rpaths-to-libraries.patch b/0001-Don-t-add-rpaths-to-libraries.patch index 6665489..6bf857a 100644 --- a/0001-Don-t-add-rpaths-to-libraries.patch +++ b/0001-Don-t-add-rpaths-to-libraries.patch @@ -1,27 +1,25 @@ -From 8ddacdf1283fe3d7054f51a4b764bc6b44d7a342 Mon Sep 17 00:00:00 2001 +From 04e523e937625bf30d775681c11e00f6dc6fc00a Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Tue, 24 Jun 2014 10:00:15 +0100 -Subject: [PATCH 1/8] Don't add rpaths to libraries. +Subject: [PATCH 1/2] Don't add rpaths to libraries. --- - tools/Makefile | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) + configure.ac | 2 -- + 1 file changed, 2 deletions(-) -diff --git a/tools/Makefile b/tools/Makefile -index 78d2a1068..fbec019ed 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -157,8 +157,8 @@ $(call byte_and_opt,ocamlmklib,ocamlmklibconfig.cmo config.cmo misc.cmo \ - ocamlmklibconfig.ml: ../config/Makefile Makefile - (echo 'let bindir = "$(BINDIR)"'; \ - echo 'let supports_shared_libraries = $(SUPPORTS_SHARED_LIBRARIES)';\ -- echo 'let default_rpath = "$(RPATH)"'; \ -- echo 'let mksharedlibrpath = "$(MKSHAREDLIBRPATH)"'; \ -+ echo 'let default_rpath = ""'; \ -+ echo 'let mksharedlibrpath = ""'; \ - echo 'let toolpref = "$(TOOLPREF)"'; \ - sed -n -e 's/^#ml //p' ../config/Makefile) \ - > ocamlmklibconfig.ml +diff --git a/configure.ac b/configure.ac +index 3754ad8a39..fb60c7c14c 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -1422,8 +1422,6 @@ AS_IF([test x"$enable_shared" != "xno"], + [[*-*-openbsd7.[3-9]|*-*-openbsd[89].*]], + [mkdll_flags="${mkdll_flags} -Wl,--no-execute-only"]) + oc_ldflags="$oc_ldflags -Wl,-E" +- rpath="-Wl,-rpath," +- mksharedlibrpath="-Wl,-rpath," + natdynlinkopts="-Wl,-E" + supports_shared_libraries=true], + [mkdll='shared-libs-not-available']) -- -2.17.1 +2.52.0 diff --git a/0002-configure-Allow-user-defined-C-compiler-flags.patch b/0002-configure-Allow-user-defined-C-compiler-flags.patch new file mode 100644 index 0000000..74de99b --- /dev/null +++ b/0002-configure-Allow-user-defined-C-compiler-flags.patch @@ -0,0 +1,25 @@ +From ef549c9a97838331877b139f407269db2a0fc691 Mon Sep 17 00:00:00 2001 +From: "Richard W.M. Jones" +Date: Tue, 29 May 2012 20:44:18 +0100 +Subject: [PATCH 2/2] configure: Allow user defined C compiler flags. + +--- + configure.ac | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index fb60c7c14c..f6a493ccf5 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -3243,7 +3243,7 @@ AC_CONFIG_COMMANDS_PRE([ + [mkexedebugflag="${mkexe_ldflags_prefix}${mkexedebugflag}"]) + mkdll_ldflags="" + AS_IF([test -n "${LDFLAGS}"], +- [for flag in ${LDFLAGS}; do ++ [for flag in "${LDFLAGS}"; do + mkdll_ldflags="${mkdll_ldflags} ${mkexe_ldflags_prefix}${flag}" + done + mkdll_ldflags_exp="$mkdll_ldflags"]) +-- +2.52.0 + diff --git a/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch b/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch deleted file mode 100644 index 9195dce..0000000 --- a/0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch +++ /dev/null @@ -1,240 +0,0 @@ -From 118057a71576cb39d71633bf80a37815bf4ff932 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 29 May 2012 20:40:36 +0100 -Subject: [PATCH 2/8] ocamlbyteinfo, ocamlplugininfo: Useful utilities from - Debian, sent upstream. - -See: -http://git.debian.org/?p=pkg-ocaml-maint/packages/ocaml.git;a=tree;f=debian/ocamlbyteinfo;hb=HEAD ---- - ocamlbyteinfo.ml | 101 +++++++++++++++++++++++++++++++++++++++++ - ocamlplugininfo.ml | 109 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 210 insertions(+) - create mode 100644 ocamlbyteinfo.ml - create mode 100644 ocamlplugininfo.ml - -diff --git a/ocamlbyteinfo.ml b/ocamlbyteinfo.ml -new file mode 100644 -index 000000000..0a537e4d5 ---- /dev/null -+++ b/ocamlbyteinfo.ml -@@ -0,0 +1,101 @@ -+(***********************************************************************) -+(* *) -+(* Objective Caml *) -+(* *) -+(* Xavier Leroy, projet Gallium, INRIA Rocquencourt *) -+(* *) -+(* Copyright 2009 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the GNU Library General Public License, with *) -+(* the special exception on linking described in file ../../LICENSE. *) -+(* *) -+(***********************************************************************) -+ -+(* $Id$ *) -+ -+(* Dumps a bytecode binary file *) -+ -+open Sys -+open Dynlinkaux -+ -+let input_stringlist ic len = -+ let get_string_list sect len = -+ let rec fold s e acc = -+ if e != len then -+ if sect.[e] = '\000' then -+ fold (e+1) (e+1) (String.sub sect s (e-s) :: acc) -+ else fold s (e+1) acc -+ else acc -+ in fold 0 0 [] -+ in -+ let sect = Bytes.create len in -+ let _ = really_input ic sect 0 len in -+ get_string_list (Bytes.to_string sect) len -+ -+let print = Printf.printf -+let perr s = -+ Printf.eprintf "%s\n" s; -+ exit(1) -+let p_title title = print "%s:\n" title -+ -+let p_section title format pdata = function -+ | [] -> () -+ | l -> -+ p_title title; -+ List.iter -+ (fun (name, data) -> print format (pdata data) name) -+ l -+ -+let p_list title format = function -+ | [] -> () -+ | l -> -+ p_title title; -+ List.iter -+ (fun name -> print format name) -+ l -+ -+let _ = -+ try -+ let input_name = Sys.argv.(1) in -+ let ic = open_in_bin input_name in -+ Bytesections.read_toc ic; -+ List.iter -+ (fun section -> -+ try -+ let len = Bytesections.seek_section ic section in -+ if len > 0 then match section with -+ | "CRCS" -> -+ p_section -+ "Imported Units" -+ "\t%s\t%s\n" -+ Digest.to_hex -+ (input_value ic : (string * Digest.t) list) -+ | "DLLS" -> -+ p_list -+ "Used Dlls" "\t%s\n" -+ (input_stringlist ic len) -+ | "DLPT" -> -+ p_list -+ "Additional Dll paths" -+ "\t%s\n" -+ (input_stringlist ic len) -+ | "PRIM" -> -+ let prims = (input_stringlist ic len) in -+ print "Uses unsafe features: "; -+ begin match prims with -+ [] -> print "no\n" -+ | l -> print "YES\n"; -+ p_list "Primitives declared in this module" -+ "\t%s\n" -+ l -+ end -+ | _ -> () -+ with Not_found | Failure _ | Invalid_argument _ -> () -+ ) -+ ["CRCS"; "DLLS"; "DLPT"; "PRIM"]; -+ close_in ic -+ with -+ | Sys_error msg -> -+ perr msg -+ | Invalid_argument("index out of bounds") -> -+ perr (Printf.sprintf "Usage: %s filename" Sys.argv.(0)) -diff --git a/ocamlplugininfo.ml b/ocamlplugininfo.ml -new file mode 100644 -index 000000000..e28800f31 ---- /dev/null -+++ b/ocamlplugininfo.ml -@@ -0,0 +1,109 @@ -+(***********************************************************************) -+(* *) -+(* Objective Caml *) -+(* *) -+(* Xavier Leroy, projet Gallium, INRIA Rocquencourt *) -+(* *) -+(* Copyright 2009 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the GNU Library General Public License, with *) -+(* the special exception on linking described in file ../../LICENSE. *) -+(* *) -+(***********************************************************************) -+ -+(* $Id$ *) -+ -+(* Dumps a .cmxs file *) -+ -+open Natdynlink -+open Format -+ -+let file = -+ try -+ Sys.argv.(1) -+ with _ -> begin -+ Printf.eprintf "Usage: %s file.cmxs\n" Sys.argv.(0); -+ exit(1) -+ end -+ -+exception Abnormal_exit -+ -+let error s e = -+ let eprint = Printf.eprintf in -+ let print_exc s = function -+ | End_of_file -> -+ eprint "%s: %s\n" s file -+ | Abnormal_exit -> -+ eprint "%s\n" s -+ | e -> eprint "%s\n" (Printexc.to_string e) -+ in -+ print_exc s e; -+ exit(1) -+ -+let read_in command = -+ let cmd = Printf.sprintf command file in -+ let ic = Unix.open_process_in cmd in -+ try -+ let line = input_line ic in -+ begin match (Unix.close_process_in ic) with -+ | Unix.WEXITED 0 -> Str.split (Str.regexp "[ ]+") line -+ | Unix.WEXITED _ | Unix.WSIGNALED _ | Unix.WSTOPPED _ -> -+ error -+ (Printf.sprintf -+ "Command \"%s\" exited abnormally" -+ cmd -+ ) -+ Abnormal_exit -+ end -+ with e -> error "File is empty" e -+ -+let get_offset adr_off adr_sec = -+ try -+ let adr = List.nth adr_off 4 in -+ let off = List.nth adr_off 5 in -+ let sec = List.hd adr_sec in -+ -+ let (!) x = Int64.of_string ("0x" ^ x) in -+ let (+) = Int64.add in -+ let (-) = Int64.sub in -+ -+ Int64.to_int (!off + !sec - !adr) -+ -+ with Failure _ | Invalid_argument _ -> -+ error -+ "Command output doesn't have the expected format" -+ Abnormal_exit -+ -+let print_infos name crc defines cmi cmx = -+ let print_name_crc (name, crc) = -+ printf "@ %s (%s)" name (Digest.to_hex crc) -+ in -+ let pr_imports ppf imps = List.iter print_name_crc imps in -+ printf "Name: %s@." name; -+ printf "CRC of implementation: %s@." (Digest.to_hex crc); -+ printf "@[Globals defined:"; -+ List.iter (fun s -> printf "@ %s" s) defines; -+ printf "@]@."; -+ printf "@[Interfaces imported:%a@]@." pr_imports cmi; -+ printf "@[Implementations imported:%a@]@." pr_imports cmx -+ -+let _ = -+ let adr_off = read_in "objdump -h %s | grep ' .data '" in -+ let adr_sec = read_in "objdump -T %s | grep ' caml_plugin_header$'" in -+ -+ let ic = open_in file in -+ let _ = seek_in ic (get_offset adr_off adr_sec) in -+ let header = (input_value ic : Natdynlink.dynheader) in -+ if header.magic <> Natdynlink.dyn_magic_number then -+ raise(Error(Natdynlink.Not_a_bytecode_file file)) -+ else begin -+ List.iter -+ (fun ui -> -+ print_infos -+ ui.name -+ ui.crc -+ ui.defines -+ ui.imports_cmi -+ ui.imports_cmx) -+ header.units -+ end --- -2.17.1 - diff --git a/0003-configure-Allow-user-defined-C-compiler-flags.patch b/0003-configure-Allow-user-defined-C-compiler-flags.patch deleted file mode 100644 index 5fb4967..0000000 --- a/0003-configure-Allow-user-defined-C-compiler-flags.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 8ddd2fb4909bf6ed1a3506723126432da8fcf0c4 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 29 May 2012 20:44:18 +0100 -Subject: [PATCH 3/8] configure: Allow user defined C compiler flags. - ---- - configure | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/configure b/configure -index 1316b3c1e..53f45f85b 100755 ---- a/configure -+++ b/configure -@@ -2050,6 +2050,10 @@ if $flat_float_array; then - echo "#define FLAT_FLOAT_ARRAY" >> m.h - fi - -+# Allow user defined C Compiler flags -+bytecccompopts="$bytecccompopts $CFLAGS" -+nativecccompopts="$nativecccompopts $CFLAGS" -+ - # Finish generated files - - cclibs="$cclibs $mathlib" --- -2.17.1 - diff --git a/0004-Add-RISC-V-backend.patch b/0004-Add-RISC-V-backend.patch deleted file mode 100644 index 22d8fe3..0000000 --- a/0004-Add-RISC-V-backend.patch +++ /dev/null @@ -1,1768 +0,0 @@ -From 38ac4778744fb7137e04708998d4e856ada1c8b8 Mon Sep 17 00:00:00 2001 -From: Nicolas Ojeda Bar -Date: Fri, 27 Oct 2017 17:05:25 +0200 -Subject: [PATCH 4/8] Add RISC-V backend - ---- - README.adoc | 1 + - asmcomp/riscv/CSE.ml | 36 ++ - asmcomp/riscv/arch.ml | 87 +++++ - asmcomp/riscv/emit.mlp | 653 ++++++++++++++++++++++++++++++++++++ - asmcomp/riscv/proc.ml | 301 +++++++++++++++++ - asmcomp/riscv/reload.ml | 16 + - asmcomp/riscv/scheduling.ml | 19 ++ - asmcomp/riscv/selection.ml | 72 ++++ - asmrun/riscv.S | 424 +++++++++++++++++++++++ - byterun/caml/stack.h | 5 + - config/gnu/config.guess | 5 +- - configure | 5 +- - 12 files changed, 1622 insertions(+), 2 deletions(-) - create mode 100644 asmcomp/riscv/CSE.ml - create mode 100644 asmcomp/riscv/arch.ml - create mode 100644 asmcomp/riscv/emit.mlp - create mode 100644 asmcomp/riscv/proc.ml - create mode 100644 asmcomp/riscv/reload.ml - create mode 100644 asmcomp/riscv/scheduling.ml - create mode 100644 asmcomp/riscv/selection.ml - create mode 100644 asmrun/riscv.S - -diff --git a/README.adoc b/README.adoc -index 74d1ec258..ac6c6eac3 100644 ---- a/README.adoc -+++ b/README.adoc -@@ -47,6 +47,7 @@ AMD64:: FreeBSD, OpenBSD, NetBSD - IA32 (Pentium):: NetBSD, OpenBSD, Solaris 9 - PowerPC:: NetBSD - ARM:: NetBSD -+RISC-V:: Linux - - Other operating systems for the processors above have not been tested, but - the compiler may work under other operating systems with little work. -diff --git a/asmcomp/riscv/CSE.ml b/asmcomp/riscv/CSE.ml -new file mode 100644 -index 000000000..302811a99 ---- /dev/null -+++ b/asmcomp/riscv/CSE.ml -@@ -0,0 +1,36 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2106 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* CSE for the RISC-V *) -+ -+open Arch -+open Mach -+open CSEgen -+ -+class cse = object (_self) -+ -+inherit cse_generic as super -+ -+method! class_of_operation op = -+ match op with -+ | Ispecific(Imultaddf _ | Imultsubf _) -> Op_pure -+ | _ -> super#class_of_operation op -+ -+method! is_cheap_operation op = -+ match op with -+ | Iconst_int n -> n <= 0x7FFn && n >= -0x800n -+ | _ -> false -+ -+end -+ -+let fundecl f = -+ (new cse)#fundecl f -diff --git a/asmcomp/riscv/arch.ml b/asmcomp/riscv/arch.ml -new file mode 100644 -index 000000000..22c807c49 ---- /dev/null -+++ b/asmcomp/riscv/arch.ml -@@ -0,0 +1,87 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Specific operations for the RISC-V processor *) -+ -+open Format -+ -+(* Machine-specific command-line options *) -+ -+let command_line_options = [] -+ -+(* Specific operations *) -+ -+type specific_operation = -+ | Imultaddf of bool (* multiply, optionally negate, and add *) -+ | Imultsubf of bool (* multiply, optionally negate, and subtract *) -+ -+let spacetime_node_hole_pointer_is_live_before = function -+ | Imultaddf _ | Imultsubf _ -> false -+ -+(* Addressing modes *) -+ -+type addressing_mode = -+ | Iindexed of int (* reg + displ *) -+ -+let is_immediate n = -+ (n <= 2047) && (n >= -2048) -+ -+(* Sizes, endianness *) -+ -+let big_endian = false -+ -+let rv64 = -+ match Config.model with "riscv64" -> true | "riscv32" -> false | _ -> assert false -+ -+let size_addr = if rv64 then 8 else 4 -+let size_int = size_addr -+let size_float = 8 -+ -+let allow_unaligned_access = false -+ -+(* Behavior of division *) -+ -+let division_crashes_on_overflow = false -+ -+(* Operations on addressing modes *) -+ -+let identity_addressing = Iindexed 0 -+ -+let offset_addressing addr delta = -+ match addr with -+ | Iindexed n -> Iindexed(n + delta) -+ -+let num_args_addressing = function -+ | Iindexed _ -> 1 -+ -+(* Printing operations and addressing modes *) -+ -+let print_addressing printreg addr ppf arg = -+ match addr with -+ | Iindexed n -> -+ let idx = if n <> 0 then Printf.sprintf " + %i" n else "" in -+ fprintf ppf "%a%s" printreg arg.(0) idx -+ -+let print_specific_operation printreg op ppf arg = -+ match op with -+ | Imultaddf false -> -+ fprintf ppf "%a *f %a +f %a" -+ printreg arg.(0) printreg arg.(1) printreg arg.(2) -+ | Imultaddf true -> -+ fprintf ppf "-f (%a *f %a +f %a)" -+ printreg arg.(0) printreg arg.(1) printreg arg.(2) -+ | Imultsubf false -> -+ fprintf ppf "%a *f %a -f %a" -+ printreg arg.(0) printreg arg.(1) printreg arg.(2) -+ | Imultsubf true -> -+ fprintf ppf "-f (%a *f %a -f %a)" -+ printreg arg.(0) printreg arg.(1) printreg arg.(2) -diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp -new file mode 100644 -index 000000000..51165d0f1 ---- /dev/null -+++ b/asmcomp/riscv/emit.mlp -@@ -0,0 +1,653 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Emission of RISC-V assembly code *) -+ -+open Misc -+open Cmm -+open Arch -+open Proc -+open Reg -+open Mach -+open Linearize -+open Emitaux -+ -+(* Layout of the stack. The stack is kept 16-aligned. *) -+ -+let stack_offset = ref 0 -+ -+let frame_size () = -+ let size = -+ !stack_offset + (* Trap frame, outgoing parameters *) -+ size_int * num_stack_slots.(0) + (* Local int variables *) -+ size_float * num_stack_slots.(1) + (* Local float variables *) -+ (if !contains_calls then size_addr else 0) in (* The return address *) -+ Misc.align size 16 -+ -+let slot_offset loc cls = -+ match loc with -+ | Local n -> -+ if cls = 0 -+ then !stack_offset + num_stack_slots.(1) * size_float + n * size_int -+ else !stack_offset + n * size_float -+ | Incoming n -> frame_size() + n -+ | Outgoing n -> n -+ -+(* Output a symbol *) -+ -+let emit_symbol s = -+ Emitaux.emit_symbol '.' s -+ -+(* Output a label *) -+ -+let label_prefix = "L" -+ -+let emit_label lbl = -+ emit_string label_prefix; emit_int lbl -+ -+(* Section switching *) -+ -+let data_space = -+ ".section .data" -+ -+let code_space = -+ ".section .text" -+ -+let rodata_space = -+ ".section .rodata" -+ -+let reg_tmp1 = phys_reg 21 (* used by the assembler *) -+let reg_tmp2 = phys_reg 22 -+let reg_t2 = phys_reg 16 -+(* let reg_fp = phys_reg 23 *) -+let reg_trap = phys_reg 24 -+let reg_alloc_ptr = phys_reg 25 -+let reg_alloc_lim = phys_reg 26 -+ -+(* Names of instructions that differ in 32 and 64-bit modes *) -+ -+let lg = if rv64 then "ld" else "lw" -+let stg = if rv64 then "sd" else "sw" -+let datag = if rv64 then ".quad" else ".long" -+ -+(* Output a pseudo-register *) -+ -+let emit_reg = function -+ | {loc = Reg r} -> emit_string (register_name r) -+ | _ -> fatal_error "Emit.emit_reg" -+ -+(* Adjust sp by the given byte amount *) -+ -+let emit_stack_adjustment = function -+ | 0 -> () -+ | n when is_immediate n -> -+ ` addi sp, sp, {emit_int n}\n` -+ | n -> -+ ` li {emit_reg reg_tmp1}, {emit_int n}\n`; -+ ` add sp, sp, {emit_reg reg_tmp1}\n` -+ -+let reload_ra n = -+ let ofs = n - size_addr in -+ if is_immediate ofs then -+ ` {emit_string lg} ra, {emit_int ofs}(sp)\n` -+ else begin -+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; -+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; -+ ` {emit_string lg} ra, 0({emit_reg reg_tmp1})\n` -+ end -+ -+let store_ra n = -+ let ofs = n - size_addr in -+ if is_immediate ofs then -+ ` {emit_string stg} ra, {emit_int(n - size_addr)}(sp)\n` -+ else begin -+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; -+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; -+ ` {emit_string stg} ra, 0({emit_reg reg_tmp1})\n` -+ end -+ -+let emit_store stg src ofs = -+ if is_immediate ofs then -+ ` {emit_string stg} {emit_reg src}, {emit_int ofs}(sp)\n` -+ else begin -+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; -+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; -+ ` {emit_string stg} {emit_reg src}, 0({emit_reg reg_tmp1})\n` -+ end -+ -+let emit_load lg dst ofs = -+ if is_immediate ofs then -+ ` {emit_string lg} {emit_reg dst}, {emit_int ofs}(sp)\n` -+ else begin -+ ` li {emit_reg reg_tmp1}, {emit_int ofs}\n`; -+ ` add {emit_reg reg_tmp1}, sp, {emit_reg reg_tmp1}\n`; -+ ` {emit_string lg} {emit_reg dst}, 0({emit_reg reg_tmp1})\n` -+ end -+ -+(* Record live pointers at call points *) -+ -+let record_frame_label ?label live raise_ dbg = -+ let lbl = -+ match label with -+ | None -> new_label() -+ | Some label -> label -+ in -+ let live_offset = ref [] in -+ Reg.Set.iter -+ (function -+ {typ = Val; loc = Reg r} -> -+ live_offset := (r lsl 1) + 1 :: !live_offset -+ | {typ = Val; loc = Stack s} as reg -> -+ live_offset := slot_offset s (register_class reg) :: !live_offset -+ | {typ = Addr} as r -> -+ Misc.fatal_error ("bad GC root " ^ Reg.name r) -+ | _ -> () -+ ) -+ live; -+ record_frame_descr ~label:lbl ~frame_size:(frame_size()) -+ ~live_offset:!live_offset ~raise_frame:raise_ dbg; -+ lbl -+ -+let record_frame ?label live raise_ dbg = -+ let lbl = record_frame_label ?label live raise_ dbg in -+ `{emit_label lbl}:\n` -+ -+(* Record calls to the GC -- we've moved them out of the way *) -+ -+type gc_call = -+ { gc_lbl: label; (* Entry label *) -+ gc_return_lbl: label; (* Where to branch after GC *) -+ gc_frame_lbl: label } (* Label of frame descriptor *) -+ -+let call_gc_sites = ref ([] : gc_call list) -+ -+let emit_call_gc gc = -+ `{emit_label gc.gc_lbl}:\n`; -+ ` call {emit_symbol "caml_call_gc"}\n`; -+ `{emit_label gc.gc_frame_lbl}:\n`; -+ ` j {emit_label gc.gc_return_lbl}\n` -+ -+(* Record calls to caml_ml_array_bound_error. -+ In debug mode, we maintain one call to caml_ml_array_bound_error -+ per bound check site. Otherwise, we can share a single call. *) -+ -+type bound_error_call = -+ { bd_lbl: label; (* Entry label *) -+ bd_frame_lbl: label } (* Label of frame descriptor *) -+ -+let bound_error_sites = ref ([] : bound_error_call list) -+ -+let bound_error_label ?label dbg = -+ if !Clflags.debug || !bound_error_sites = [] then begin -+ let lbl_bound_error = new_label() in -+ let lbl_frame = record_frame_label ?label Reg.Set.empty false dbg in -+ bound_error_sites := -+ { bd_lbl = lbl_bound_error; -+ bd_frame_lbl = lbl_frame } :: !bound_error_sites; -+ lbl_bound_error -+ end else -+ let bd = List.hd !bound_error_sites in -+ bd.bd_lbl -+ -+let emit_call_bound_error bd = -+ `{emit_label bd.bd_lbl}:\n`; -+ ` call {emit_symbol "caml_ml_array_bound_error"}\n`; -+ `{emit_label bd.bd_frame_lbl}:\n` -+ -+(* Record floating-point literals *) -+ -+let float_literals = ref ([] : (int64 * int) list) -+ -+(* Names for various instructions *) -+ -+let name_for_intop = function -+ | Iadd -> "add" -+ | Isub -> "sub" -+ | Imul -> "mul" -+ | Imulh -> "mulh" -+ | Idiv -> "div" -+ | Iand -> "and" -+ | Ior -> "or" -+ | Ixor -> "xor" -+ | Ilsl -> "sll" -+ | Ilsr -> "srl" -+ | Iasr -> "sra" -+ | Imod -> "rem" -+ | _ -> fatal_error "Emit.Intop" -+ -+let name_for_intop_imm = function -+ | Iadd -> "addi" -+ | Iand -> "andi" -+ | Ior -> "ori" -+ | Ixor -> "xori" -+ | Ilsl -> "slli" -+ | Ilsr -> "srli" -+ | Iasr -> "srai" -+ | _ -> fatal_error "Emit.Intop_imm" -+ -+let name_for_floatop1 = function -+ | Inegf -> "fneg.d" -+ | Iabsf -> "fabs.d" -+ | _ -> fatal_error "Emit.Iopf1" -+ -+let name_for_floatop2 = function -+ | Iaddf -> "fadd.d" -+ | Isubf -> "fsub.d" -+ | Imulf -> "fmul.d" -+ | Idivf -> "fdiv.d" -+ | _ -> fatal_error "Emit.Iopf2" -+ -+let name_for_specific = function -+ | Imultaddf false -> "fmadd.d" -+ | Imultaddf true -> "fnmadd.d" -+ | Imultsubf false -> "fmsub.d" -+ | Imultsubf true -> "fnmsub.d" -+ -+(* Name of current function *) -+let function_name = ref "" -+ -+(* Entry point for tail recursive calls *) -+let tailrec_entry_point = ref 0 -+ -+(* Output the assembly code for an instruction *) -+ -+let emit_instr i = -+ match i.desc with -+ Lend -> () -+ | Lop(Imove | Ispill | Ireload) -> -+ let src = i.arg.(0) and dst = i.res.(0) in -+ if src.loc <> dst.loc then begin -+ match (src, dst) with -+ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Reg _} -> -+ ` mv {emit_reg dst}, {emit_reg src}\n` -+ | {loc = Reg _; typ = Float}, {loc = Reg _; typ = Float} -> -+ ` fmv.d {emit_reg dst}, {emit_reg src}\n` -+ | {loc = Reg _; typ = (Val | Int | Addr)}, {loc = Stack s} -> -+ let ofs = slot_offset s (register_class dst) in -+ emit_store stg src ofs -+ | {loc = Reg _; typ = Float}, {loc = Stack s} -> -+ let ofs = slot_offset s (register_class dst) in -+ emit_store "fsd" src ofs -+ | {loc = Stack s; typ = (Val | Int | Addr)}, {loc = Reg _} -> -+ let ofs = slot_offset s (register_class src) in -+ emit_load lg dst ofs -+ | {loc = Stack s; typ = Float}, {loc = Reg _} -> -+ let ofs = slot_offset s (register_class src) in -+ emit_load "fld" dst ofs -+ | _ -> -+ fatal_error "Emit: Imove" -+ end -+ | Lop(Iconst_int n) -> -+ ` li {emit_reg i.res.(0)}, {emit_nativeint n}\n` -+ | Lop(Iconst_float f) -> -+ let lbl = new_label() in -+ float_literals := (f, lbl) :: !float_literals; -+ ` fld {emit_reg i.res.(0)}, {emit_label lbl}, {emit_reg reg_tmp1}\n` -+ | Lop(Iconst_symbol s) -> -+ ` la {emit_reg i.res.(0)}, {emit_symbol s}\n` -+ | Lop(Icall_ind {label_after = label}) -> -+ ` jalr {emit_reg i.arg.(0)}\n`; -+ record_frame ~label i.live false i.dbg -+ | Lop(Icall_imm {func; label_after = label}) -> -+ ` call {emit_symbol func}\n`; -+ record_frame ~label i.live false i.dbg -+ | Lop(Itailcall_ind {label_after = _}) -> -+ let n = frame_size() in -+ if !contains_calls then reload_ra n; -+ emit_stack_adjustment n; -+ ` jr {emit_reg i.arg.(0)}\n` -+ | Lop(Itailcall_imm {func; label_after = _}) -> -+ if func = !function_name then begin -+ ` j {emit_label !tailrec_entry_point}\n` -+ end else begin -+ let n = frame_size() in -+ if !contains_calls then reload_ra n; -+ emit_stack_adjustment n; -+ ` tail {emit_symbol func}\n` -+ end -+ | Lop(Iextcall{func; alloc = true; label_after = label}) -> -+ ` la {emit_reg reg_t2}, {emit_symbol func}\n`; -+ ` call {emit_symbol "caml_c_call"}\n`; -+ record_frame ~label i.live false i.dbg -+ | Lop(Iextcall{func; alloc = false; label_after = _}) -> -+ ` call {emit_symbol func}\n` -+ | Lop(Istackoffset n) -> -+ assert (n mod 16 = 0); -+ emit_stack_adjustment (-n); -+ stack_offset := !stack_offset + n -+ | Lop(Iload(Single, Iindexed ofs)) -> -+ ` flw {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n`; -+ ` fcvt.d.s {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` -+ | Lop(Iload(chunk, Iindexed ofs)) -> -+ let instr = -+ match chunk with -+ | Byte_unsigned -> "lbu" -+ | Byte_signed -> "lb" -+ | Sixteen_unsigned -> "lhu" -+ | Sixteen_signed -> "lh" -+ | Thirtytwo_unsigned -> if rv64 then "lwu" else "lw" -+ | Thirtytwo_signed -> "lw" -+ | Word_int | Word_val -> lg -+ | Single -> assert false -+ | Double | Double_u -> "fld" -+ in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_int ofs}({emit_reg i.arg.(0)})\n` -+ | Lop(Istore(Single, Iindexed ofs, _)) -> -+ ` fmv.x.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}\n`; -+ ` fcvt.s.d {emit_reg i.arg.(0)}, {emit_reg i.arg.(0)}\n`; -+ ` fsw {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n`; -+ ` fmv.d.x {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}\n` -+ | Lop(Istore(chunk, Iindexed ofs, _)) -> -+ let instr = -+ match chunk with -+ | Byte_unsigned | Byte_signed -> "sb" -+ | Sixteen_unsigned | Sixteen_signed -> "sh" -+ | Thirtytwo_unsigned | Thirtytwo_signed -> "sw" -+ | Word_int | Word_val -> stg -+ | Single -> assert false -+ | Double | Double_u -> "fsd" -+ in -+ ` {emit_string instr} {emit_reg i.arg.(0)}, {emit_int ofs}({emit_reg i.arg.(1)})\n` -+ | Lop(Ialloc {words = n; label_after_call_gc = label; _}) -> -+ let lbl_frame_lbl = record_frame_label ?label i.live false i.dbg in -+ let lbl_redo = new_label () in -+ let lbl_call_gc = new_label () in -+ `{emit_label lbl_redo}:\n`; -+ ` addi {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_ptr}, -{emit_int n}\n`; -+ ` addi {emit_reg i.res.(0)}, {emit_reg reg_alloc_ptr}, {emit_int size_addr}\n`; -+ ` bltu {emit_reg reg_alloc_ptr}, {emit_reg reg_alloc_lim}, {emit_label lbl_call_gc}\n`; -+ call_gc_sites := -+ { gc_lbl = lbl_call_gc; -+ gc_return_lbl = lbl_redo; -+ gc_frame_lbl = lbl_frame_lbl } :: !call_gc_sites -+ | Lop(Iintop(Icomp cmp)) -> -+ begin match cmp with -+ | Isigned Clt -> -+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | Isigned Cge -> -+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; -+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; -+ | Isigned Cgt -> -+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` -+ | Isigned Cle -> -+ ` slt {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; -+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; -+ | Isigned Ceq | Iunsigned Ceq -> -+ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; -+ ` seqz {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` -+ | Isigned Cne | Iunsigned Cne -> -+ ` sub {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; -+ ` snez {emit_reg i.res.(0)}, {emit_reg i.res.(0)}\n` -+ | Iunsigned Clt -> -+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | Iunsigned Cge -> -+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; -+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; -+ | Iunsigned Cgt -> -+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` -+ | Iunsigned Cle -> -+ ` sltu {emit_reg i.res.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; -+ ` xori {emit_reg i.res.(0)}, {emit_reg i.res.(0)}, 1\n`; -+ end -+ | Lop(Iintop (Icheckbound {label_after_error = label; _})) -> -+ let lbl = bound_error_label ?label i.dbg in -+ ` bleu {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` -+ | Lop(Iintop op) -> -+ let instr = name_for_intop op in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | Lop(Iintop_imm(Isub, n)) -> -+ ` addi {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int(-n)}\n` -+ | Lop(Iintop_imm(Icomp _, _)) -> -+ fatal_error "Emit.emit_instr (Iintop_imm (Icomp _, _))" -+ | Lop(Iintop_imm(Icheckbound {label_after_error = label; _}, n)) -> -+ let lbl = bound_error_label ?label i.dbg in -+ ` li {emit_reg reg_tmp1}, {emit_int n}\n`; -+ ` bleu {emit_reg i.arg.(0)}, {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ | Lop(Iintop_imm(op, n)) -> -+ let instr = name_for_intop_imm op in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_int n}\n` -+ | Lop(Inegf | Iabsf as op) -> -+ let instr = name_for_floatop1 op in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` -+ | Lop(Iaddf | Isubf | Imulf | Idivf as op) -> -+ let instr = name_for_floatop2 op in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | Lop(Ifloatofint) -> -+ let name = if rv64 then "fcvt.d.l" else "fcvt.d.w" in -+ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` -+ | Lop(Iintoffloat) -> -+ let name = if rv64 then "fcvt.l.d" else "fcvt.w.d" in -+ ` {emit_string name} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}\n` -+ | Lop(Ispecific sop) -> -+ let instr = name_for_specific sop in -+ ` {emit_string instr} {emit_reg i.res.(0)}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(2)}\n` -+ | Lop (Iname_for_debugger _) -> -+ () -+ | Lreloadretaddr -> -+ let n = frame_size () in -+ reload_ra n -+ | Lreturn -> -+ let n = frame_size() in -+ emit_stack_adjustment n; -+ ` ret\n` -+ | Llabel lbl -> -+ `{emit_label lbl}:\n` -+ | Lbranch lbl -> -+ ` j {emit_label lbl}\n` -+ | Lcondbranch(tst, lbl) -> -+ begin match tst with -+ | Itruetest -> -+ ` bnez {emit_reg i.arg.(0)}, {emit_label lbl}\n` -+ | Ifalsetest -> -+ ` beqz {emit_reg i.arg.(0)}, {emit_label lbl}\n` -+ | Iinttest cmp -> -+ let name = match cmp with -+ | Iunsigned Ceq | Isigned Ceq -> "beq" -+ | Iunsigned Cne | Isigned Cne -> "bne" -+ | Iunsigned Cle -> "bleu" | Isigned Cle -> "ble" -+ | Iunsigned Cge -> "bgeu" | Isigned Cge -> "bge" -+ | Iunsigned Clt -> "bltu" | Isigned Clt -> "blt" -+ | Iunsigned Cgt -> "bgtu" | Isigned Cgt -> "bgt" -+ in -+ ` {emit_string name} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` -+ | Iinttest_imm _ -> -+ fatal_error "Emit.emit_instr (Iinttest_imm _)" -+ | Ifloattest(cmp, neg) -> -+ let neg = match cmp with -+ | Ceq -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -+ | Cne -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; not neg -+ | Clt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -+ | Cgt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg -+ | Cle -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -+ | Cge -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg -+ in -+ if neg then -+ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ else -+ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ | Ioddtest -> -+ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; -+ ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ | Ieventest -> -+ ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; -+ ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ end -+ | Lcondbranch3(lbl0, lbl1, lbl2) -> -+ ` addi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, -1\n`; -+ begin match lbl0 with -+ | None -> () -+ | Some lbl -> ` bltz {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ end; -+ begin match lbl1 with -+ | None -> () -+ | Some lbl -> ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ end; -+ begin match lbl2 with -+ | None -> () -+ | Some lbl -> ` bgtz {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ end -+ | Lswitch jumptbl -> (* FIXME FIXME ? *) -+ let lbl = new_label() in -+ ` la {emit_reg reg_tmp1}, {emit_label lbl}\n`; -+ ` slli {emit_reg reg_tmp2}, {emit_reg i.arg.(0)}, 2\n`; -+ ` add {emit_reg reg_tmp1}, {emit_reg reg_tmp1}, {emit_reg reg_tmp2}\n`; -+ ` jr {emit_reg reg_tmp1}\n`; -+ `{emit_label lbl}:\n`; -+ for i = 0 to Array.length jumptbl - 1 do -+ ` j {emit_label jumptbl.(i)}\n` -+ done -+ | Lsetuptrap lbl -> -+ ` addi sp, sp, -16\n`; -+ ` jal {emit_label lbl}\n` -+ | Lpushtrap -> -+ stack_offset := !stack_offset + 16; -+ ` {emit_string stg} ra, {emit_int size_addr}(sp)\n`; -+ ` {emit_string stg} {emit_reg reg_trap}, 0(sp)\n`; -+ ` mv {emit_reg reg_trap}, sp\n` -+ | Lpoptrap -> -+ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`; -+ ` addi sp, sp, 16\n`; -+ stack_offset := !stack_offset - 16 -+ | Lraise k -> -+ begin match !Clflags.debug, k with -+ | true, Cmm.Raise_withtrace -> -+ ` call {emit_symbol "caml_raise_exn"}\n`; -+ record_frame Reg.Set.empty true i.dbg -+ | false, _ -+ | true, Cmm.Raise_notrace -> -+ ` mv sp, {emit_reg reg_trap}\n`; -+ ` {emit_string lg} {emit_reg reg_tmp1}, {emit_int size_addr}(sp)\n`; -+ ` {emit_string lg} {emit_reg reg_trap}, 0(sp)\n`; -+ ` addi sp, sp, 16\n`; -+ ` jalr {emit_reg reg_tmp1}\n` -+ end -+ -+(* Emit a sequence of instructions *) -+ -+let rec emit_all = function -+ | {desc = Lend} -> () | i -> emit_instr i; emit_all i.next -+ -+(* Emission of a function declaration *) -+ -+let fundecl fundecl = -+ function_name := fundecl.fun_name; -+ tailrec_entry_point := new_label(); -+ stack_offset := 0; -+ call_gc_sites := []; -+ bound_error_sites := []; -+ float_literals := []; -+ ` .globl {emit_symbol fundecl.fun_name}\n`; -+ ` .type {emit_symbol fundecl.fun_name}, @function\n`; -+ ` {emit_string code_space}\n`; -+ ` .align 2\n`; -+ `{emit_symbol fundecl.fun_name}:\n`; -+ let n = frame_size() in -+ emit_stack_adjustment (-n); -+ if !contains_calls then store_ra n; -+ `{emit_label !tailrec_entry_point}:\n`; -+ emit_all fundecl.fun_body; -+ List.iter emit_call_gc !call_gc_sites; -+ List.iter emit_call_bound_error !bound_error_sites; -+ ` .size {emit_symbol fundecl.fun_name}, .-{emit_symbol fundecl.fun_name}\n`; -+ (* Emit the float literals *) -+ if !float_literals <> [] then begin -+ ` {emit_string rodata_space}\n`; -+ ` .align 3\n`; -+ List.iter -+ (fun (f, lbl) -> -+ `{emit_label lbl}:\n`; -+ if rv64 -+ then emit_float64_directive ".quad" f -+ else emit_float64_split_directive ".long" f) -+ !float_literals; -+ end -+ -+(* Emission of data *) -+ -+let declare_global_data s = -+ ` .globl {emit_symbol s}\n`; -+ ` .type {emit_symbol s}, @object\n` -+ -+let emit_item = function -+ | Cglobal_symbol s -> -+ declare_global_data s -+ | Cdefine_symbol s -> -+ `{emit_symbol s}:\n`; -+ | Cint8 n -> -+ ` .byte {emit_int n}\n` -+ | Cint16 n -> -+ ` .short {emit_int n}\n` -+ | Cint32 n -> -+ ` .long {emit_nativeint n}\n` -+ | Cint n -> -+ ` {emit_string datag} {emit_nativeint n}\n` -+ | Csingle f -> -+ emit_float32_directive ".long" (Int32.bits_of_float f) -+ | Cdouble f -> -+ if rv64 -+ then emit_float64_directive ".quad" (Int64.bits_of_float f) -+ else emit_float64_split_directive ".long" (Int64.bits_of_float f) -+ | Csymbol_address s -> -+ ` {emit_string datag} {emit_symbol s}\n` -+ | Cstring s -> -+ emit_bytes_directive " .byte " s -+ | Cskip n -> -+ if n > 0 then ` .space {emit_int n}\n` -+ | Calign n -> -+ ` .align {emit_int (Misc.log2 n)}\n` -+ -+let data l = -+ ` {emit_string data_space}\n`; -+ List.iter emit_item l -+ -+(* Beginning / end of an assembly file *) -+ -+let begin_assembly() = -+ ` .file \"\"\n`; (* PR#7073 *) -+ (* Emit the beginning of the segments *) -+ let lbl_begin = Compilenv.make_symbol (Some "data_begin") in -+ ` {emit_string data_space}\n`; -+ declare_global_data lbl_begin; -+ `{emit_symbol lbl_begin}:\n`; -+ let lbl_begin = Compilenv.make_symbol (Some "code_begin") in -+ ` {emit_string code_space}\n`; -+ declare_global_data lbl_begin; -+ `{emit_symbol lbl_begin}:\n` -+ -+let end_assembly() = -+ ` {emit_string code_space}\n`; -+ let lbl_end = Compilenv.make_symbol (Some "code_end") in -+ declare_global_data lbl_end; -+ `{emit_symbol lbl_end}:\n`; -+ ` .long 0\n`; -+ ` {emit_string data_space}\n`; -+ let lbl_end = Compilenv.make_symbol (Some "data_end") in -+ declare_global_data lbl_end; -+ `{emit_symbol lbl_end}:\n`; -+ ` {emit_string datag} 0\n`; -+ (* Emit the frame descriptors *) -+ ` {emit_string rodata_space}\n`; -+ let lbl = Compilenv.make_symbol (Some "frametable") in -+ declare_global_data lbl; -+ `{emit_symbol lbl}:\n`; -+ emit_frames -+ { efa_code_label = (fun l -> ` {emit_string datag} {emit_label l}\n`); -+ efa_data_label = (fun l -> ` {emit_string datag} {emit_label l}\n`); -+ efa_16 = (fun n -> ` .short {emit_int n}\n`); -+ efa_32 = (fun n -> ` .long {emit_int32 n}\n`); -+ efa_word = (fun n -> ` {emit_string datag} {emit_int n}\n`); -+ efa_align = (fun n -> ` .align {emit_int (Misc.log2 n)}\n`); -+ efa_label_rel = (fun lbl ofs -> -+ ` .long ({emit_label lbl} - .) + {emit_int32 ofs}\n`); -+ efa_def_label = (fun l -> `{emit_label l}:\n`); -+ efa_string = (fun s -> emit_bytes_directive " .byte " (s ^ "\000")) -+ } -diff --git a/asmcomp/riscv/proc.ml b/asmcomp/riscv/proc.ml -new file mode 100644 -index 000000000..c0b0dcdb8 ---- /dev/null -+++ b/asmcomp/riscv/proc.ml -@@ -0,0 +1,301 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Description of the RISC-V *) -+ -+open Misc -+open Cmm -+open Reg -+open Arch -+open Mach -+ -+(* Instruction selection *) -+ -+let word_addressed = false -+ -+(* Registers available for register allocation *) -+ -+(* Integer register map: -+ zero always zero -+ ra return address -+ sp, gp, tp stack pointer, global pointer, thread pointer (preserved by C) -+ a0 - a7 0 - 7 arguments/results -+ s2 - s9 8 - 15 arguments/results (preserved by C) -+ t2 - t6 16 - 20 temporary -+ t0 21 temporary (used by assembler) -+ t1 22 temporary (reserved for code gen) -+ s0 23 frame pointer (preserved by C) -+ s1 24 trap pointer (preserved by C) -+ s10 25 allocation pointer (preserved by C) -+ s11 26 allocation limit (preserved by C) -+ Floating-point register map: -+ ft0 - ft7 100 - 107 temporary -+ fs0 - fs1 108 - 109 general purpose (preserved by C) -+ fa0 - fa7 110 - 117 arguments/results -+ fs2 - fs9 118 - 125 arguments/results (preserved by C) -+ fs10 - fs11 126 - 127 general purpose (preserved by C) -+ ft8 - ft11 128 - 131 temporary -+*) -+ -+let int_reg_name = -+ [| "a0"; "a1"; "a2"; "a3"; "a4"; "a5"; "a6"; "a7"; -+ "s2"; "s3"; "s4"; "s5"; "s6"; "s7"; "s8"; "s9"; -+ "t2"; "t3"; "t4"; "t5"; "t6"; -+ "t0"; "t1"; -+ "s0"; "s1"; "s10"; "s11" |] -+ -+let float_reg_name = -+ [| "ft0"; "ft1"; "ft2"; "ft3"; "ft4"; "ft5"; "ft6"; "ft7"; -+ "fs0"; "fs1"; -+ "fa0"; "fa1"; "fa2"; "fa3"; "fa4"; "fa5"; "fa6"; "fa7"; -+ "fs2"; "fs3"; "fs4"; "fs5"; "fs6"; "fs7"; "fs8"; "fs9"; "fs10"; "fs11"; -+ "ft8"; "ft9"; "ft10"; "ft11" |] -+ -+let num_register_classes = 2 -+ -+let register_class r = -+ match r.typ with -+ | Val | Int | Addr -> 0 -+ | Float -> 1 -+ -+let num_available_registers = [| 21; 32 |] -+ -+let first_available_register = [| 0; 100 |] -+ -+let register_name r = -+ if r < 100 then int_reg_name.(r) else float_reg_name.(r - 100) -+ -+let rotate_registers = true -+ -+(* Representation of hard registers by pseudo-registers *) -+ -+let hard_int_reg = -+ let v = Array.make 27 Reg.dummy in -+ for i = 0 to 26 do -+ v.(i) <- Reg.at_location Int (Reg i) -+ done; -+ v -+ -+let hard_float_reg = -+ let v = Array.make 32 Reg.dummy in -+ for i = 0 to 31 do -+ v.(i) <- Reg.at_location Float (Reg(100 + i)) -+ done; -+ v -+ -+let all_phys_regs = -+ Array.append hard_int_reg hard_float_reg -+ -+let phys_reg n = -+ if n < 100 then hard_int_reg.(n) else hard_float_reg.(n - 100) -+ -+let stack_slot slot ty = -+ Reg.at_location ty (Stack slot) -+ -+(* Calling conventions *) -+ -+let calling_conventions -+ first_int last_int first_float last_float make_stack arg = -+ let loc = Array.make (Array.length arg) Reg.dummy in -+ let int = ref first_int in -+ let float = ref first_float in -+ let ofs = ref 0 in -+ for i = 0 to Array.length arg - 1 do -+ match arg.(i).typ with -+ | Val | Int | Addr as ty -> -+ if !int <= last_int then begin -+ loc.(i) <- phys_reg !int; -+ incr int -+ end else begin -+ loc.(i) <- stack_slot (make_stack !ofs) ty; -+ ofs := !ofs + size_int -+ end -+ | Float -> -+ if !float <= last_float then begin -+ loc.(i) <- phys_reg !float; -+ incr float -+ end else begin -+ loc.(i) <- stack_slot (make_stack !ofs) Float; -+ ofs := !ofs + size_float -+ end -+ done; -+ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *) -+ -+let incoming ofs = Incoming ofs -+let outgoing ofs = Outgoing ofs -+let not_supported _ = fatal_error "Proc.loc_results: cannot call" -+ -+let max_arguments_for_tailcalls = 16 -+ -+let loc_spacetime_node_hole = Reg.dummy (* Spacetime unsupported *) -+ -+(* OCaml calling convention: -+ first integer args in a0 .. a7, s2 .. s9 -+ first float args in fa0 .. fa7, fs2 .. fs9 -+ remaining args on stack. -+ Return values in a0 .. a7, s2 .. s9 or fa0 .. fa7, fs2 .. fs9. *) -+ -+let single_regs arg = Array.map (fun arg -> [| arg |]) arg -+let ensure_single_regs res = -+ Array.map (function -+ | [| res |] -> res -+ | _ -> failwith "proc.ensure_single_regs" -+ ) res -+ -+let loc_arguments arg = -+ calling_conventions 0 15 110 125 outgoing arg -+ -+let loc_parameters arg = -+ let (loc, _ofs) = -+ calling_conventions 0 15 110 125 incoming arg -+ in -+ loc -+ -+let loc_results res = -+ let (loc, _ofs) = -+ calling_conventions 0 15 110 125 not_supported res -+ in -+ loc -+ -+(* C calling convention: -+ first integer args in a0 .. a7 -+ first float args in fa0 .. fa7 -+ remaining args on stack. -+ Return values in a0 .. a1 or fa0 .. fa1. *) -+ -+let external_calling_conventions -+ first_int last_int first_float last_float make_stack arg = -+ let loc = Array.make (Array.length arg) [| Reg.dummy |] in -+ let int = ref first_int in -+ let float = ref first_float in -+ let ofs = ref 0 in -+ for i = 0 to Array.length arg - 1 do -+ match arg.(i) with -+ | [| arg |] -> -+ begin match arg.typ with -+ | Val | Int | Addr as ty -> -+ if !int <= last_int then begin -+ loc.(i) <- [| phys_reg !int |]; -+ incr int; -+ incr float; -+ end else begin -+ loc.(i) <- [| stack_slot (make_stack !ofs) ty |]; -+ ofs := !ofs + size_int -+ end -+ | Float -> -+ if !float <= last_float then begin -+ loc.(i) <- [| phys_reg !float |]; -+ incr float; -+ incr int; -+ end else begin -+ loc.(i) <- [| stack_slot (make_stack !ofs) Float |]; -+ ofs := !ofs + size_float -+ end -+ end -+ | [| arg1; arg2 |] -> -+ (* Passing of 64-bit quantities to external functions on 32-bit -+ platform. *) -+ assert (size_int = 4); -+ begin match arg1.typ, arg2.typ with -+ | Int, Int -> -+ int := Misc.align !int 2; -+ if !int <= last_int - 1 then begin -+ let reg_lower = phys_reg !int in -+ let reg_upper = phys_reg (!int + 1) in -+ loc.(i) <- [| reg_lower; reg_upper |]; -+ int := !int + 2 -+ end else begin -+ let size_int64 = 8 in -+ ofs := Misc.align !ofs size_int64; -+ let ofs_lower = !ofs in -+ let ofs_upper = !ofs + size_int in -+ let stack_lower = stack_slot (make_stack ofs_lower) Int in -+ let stack_upper = stack_slot (make_stack ofs_upper) Int in -+ loc.(i) <- [| stack_lower; stack_upper |]; -+ ofs := !ofs + size_int64 -+ end -+ | _ -> -+ let f = function Int -> "I" | Addr -> "A" | Val -> "V" | Float -> "F" in -+ fatal_error (Printf.sprintf "Proc.calling_conventions: bad register \ -+ type(s) for multi-register argument: %s, %s" -+ (f arg1.typ) (f arg2.typ)) -+ end -+ | _ -> -+ fatal_error "Proc.calling_conventions: bad number of register for \ -+ multi-register argument" -+ done; -+ (loc, Misc.align !ofs 16) (* Keep stack 16-aligned. *) -+ -+let loc_external_arguments arg = -+ external_calling_conventions 0 7 110 117 outgoing arg -+ -+let loc_external_results res = -+ let (loc, _ofs) = -+ external_calling_conventions 0 1 110 111 not_supported (single_regs res) -+ in -+ ensure_single_regs loc -+ -+(* Exceptions are in GPR 3 *) -+ -+let loc_exn_bucket = phys_reg 0 -+ -+(* Volatile registers: none *) -+ -+let regs_are_volatile _ = false -+ -+(* Registers destroyed by operations *) -+ -+let destroyed_at_c_call = -+ Array.of_list(List.map phys_reg -+ [0; 1; 2; 3; 4; 5; 6; 7; 16; 17; 18; 19; 20; (* 21; 22; *) -+ 100; 101; 102; 103; 104; 105; 106; 107; 110; 111; 112; 113; 114; 115; 116; -+ 117; 128; 129; 130; 131]) -+ -+let destroyed_at_oper = function -+ | Iop(Icall_ind _ | Icall_imm _ | Iextcall{alloc = true; _}) -> all_phys_regs -+ | Iop(Iextcall{alloc = false; _}) -> destroyed_at_c_call -+ | _ -> [||] -+ -+let destroyed_at_raise = all_phys_regs -+ -+(* Maximal register pressure *) -+ -+let safe_register_pressure = function -+ | Iextcall _ -> 15 -+ | _ -> 21 -+ -+let max_register_pressure = function -+ | Iextcall _ -> [| 15; 18 |] -+ | _ -> [| 21; 30 |] -+ -+(* Pure operations (without any side effect besides updating their result -+ registers). *) -+ -+let op_is_pure = function -+ | Icall_ind _ | Icall_imm _ | Itailcall_ind _ | Itailcall_imm _ -+ | Iextcall _ | Istackoffset _ | Istore _ | Ialloc _ -+ | Iintop(Icheckbound _) | Iintop_imm(Icheckbound _, _) -> false -+ | Ispecific(Imultaddf _ | Imultsubf _) -> true -+ | _ -> true -+ -+(* Layout of the stack *) -+ -+let num_stack_slots = [| 0; 0 |] -+let contains_calls = ref false -+ -+(* Calling the assembler *) -+ -+let assemble_file infile outfile = -+ Ccomp.command -+ (Config.asm ^ " -o " ^ Filename.quote outfile ^ " " ^ Filename.quote infile) -+ -+let init () = () -diff --git a/asmcomp/riscv/reload.ml b/asmcomp/riscv/reload.ml -new file mode 100644 -index 000000000..85b970342 ---- /dev/null -+++ b/asmcomp/riscv/reload.ml -@@ -0,0 +1,16 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Reloading for the RISC-V *) -+ -+let fundecl f = -+ (new Reloadgen.reload_generic)#fundecl f -diff --git a/asmcomp/riscv/scheduling.ml b/asmcomp/riscv/scheduling.ml -new file mode 100644 -index 000000000..e436be1cc ---- /dev/null -+++ b/asmcomp/riscv/scheduling.ml -@@ -0,0 +1,19 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Instruction scheduling for the RISC-V *) -+ -+let _ = let module M = Schedgen in () (* to create a dependency *) -+ -+(* Scheduling is turned off. *) -+ -+let fundecl f = f -diff --git a/asmcomp/riscv/selection.ml b/asmcomp/riscv/selection.ml -new file mode 100644 -index 000000000..092ca88aa ---- /dev/null -+++ b/asmcomp/riscv/selection.ml -@@ -0,0 +1,72 @@ -+(***********************************************************************) -+(* *) -+(* OCaml *) -+(* *) -+(* Nicolas Ojeda Bar *) -+(* *) -+(* Copyright 2016 Institut National de Recherche en Informatique et *) -+(* en Automatique. All rights reserved. This file is distributed *) -+(* under the terms of the Q Public License version 1.0. *) -+(* *) -+(***********************************************************************) -+ -+(* Instruction selection for the RISC-V processor *) -+ -+open Cmm -+open Arch -+open Mach -+ -+(* Instruction selection *) -+ -+class selector = object (self) -+ -+inherit Selectgen.selector_generic as super -+ -+method is_immediate n = is_immediate n -+ -+method select_addressing _ = function -+ | Cop(Cadda, [arg; Cconst_int n], _) when self#is_immediate n -> -+ (Iindexed n, arg) -+ | Cop(Cadda, [arg1; Cop(Caddi, [arg2; Cconst_int n], _)], dbg) when self#is_immediate n -> -+ (Iindexed n, Cop(Caddi, [arg1; arg2], dbg)) -+ | arg -> -+ (Iindexed 0, arg) -+ -+method! select_operation op args dbg = -+ match (op, args) with -+ (* RISC-V does not support immediate operands for multiply high *) -+ | (Cmulhi, _) -> (Iintop Imulh, args) -+ (* Recognize (neg-)mult-add and (neg-)mult-sub instructions *) -+ | (Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3]) -+ | (Caddf, [arg3; Cop(Cmulf, [arg1; arg2], _)]) -> -+ (Ispecific (Imultaddf false), [arg1; arg2; arg3]) -+ | (Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3]) -> -+ (Ispecific (Imultsubf false), [arg1; arg2; arg3]) -+ | (Cnegf, [Cop(Csubf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> -+ (Ispecific (Imultsubf true), [arg1; arg2; arg3]) -+ | (Cnegf, [Cop(Caddf, [Cop(Cmulf, [arg1; arg2], _); arg3], _)]) -> -+ (Ispecific (Imultaddf true), [arg1; arg2; arg3]) -+ (* RISC-V does not support immediate operands for comparison operators *) -+ | (Ccmpi comp, args) -> (Iintop(Icomp (Isigned comp)), args) -+ | (Ccmpa comp, args) -> (Iintop(Icomp (Iunsigned comp)), args) -+ | (Cmuli, _) -> (Iintop Imul, args) -+ | _ -> -+ super#select_operation op args dbg -+ -+(* Instruction selection for conditionals *) -+ -+method! select_condition = function -+ | Cop(Ccmpi cmp, args, _) -> -+ (Iinttest(Isigned cmp), Ctuple args) -+ | Cop(Ccmpa cmp, args, _) -> -+ (Iinttest(Iunsigned cmp), Ctuple args) -+ | Cop(Ccmpf cmp, args, _) -> -+ (Ifloattest(cmp, false), Ctuple args) -+ | Cop(Cand, [arg; Cconst_int 1], _) -> -+ (Ioddtest, arg) -+ | arg -> -+ (Itruetest, arg) -+ -+end -+ -+let fundecl f = (new selector)#emit_fundecl f -diff --git a/asmrun/riscv.S b/asmrun/riscv.S -new file mode 100644 -index 000000000..a82048efc ---- /dev/null -+++ b/asmrun/riscv.S -@@ -0,0 +1,424 @@ -+/***********************************************************************/ -+/* */ -+/* OCaml */ -+/* */ -+/* Nicolas Ojeda Bar */ -+/* */ -+/* Copyright 1996 Institut National de Recherche en Informatique et */ -+/* en Automatique. All rights reserved. This file is distributed */ -+/* under the terms of the GNU Library General Public License, with */ -+/* the special exception on linking described in file ../LICENSE. */ -+/* */ -+/***********************************************************************/ -+ -+/* Asm part of the runtime system, RISC-V processor, 64-bit mode */ -+/* Must be preprocessed by cpp */ -+ -+#define TRAP_PTR s1 -+#define ALLOC_PTR s10 -+#define ALLOC_LIMIT s11 -+#define TMP0 t0 -+#define TMP1 t1 -+#define ARG t2 -+ -+#if defined(MODEL_riscv64) -+#define store sd -+#define load ld -+#define WSZ 8 -+#else -+#define store sw -+#define load lw -+#define WSZ 4 -+#endif -+ -+#if defined(__PIC__) -+ .option pic -+#else -+ .option nopic -+#endif -+ -+ .section .text -+/* Invoke the garbage collector. */ -+ -+ .globl caml_system__code_begin -+caml_system__code_begin: -+ -+ .align 2 -+ .globl caml_call_gc -+ .type caml_call_gc, @function -+caml_call_gc: -+ /* Record return address */ -+ store ra, caml_last_return_address, TMP0 -+ /* Record lowest stack address */ -+ mv TMP1, sp -+ store sp, caml_bottom_of_stack, TMP0 -+.Lcaml_call_gc: -+ /* Set up stack space, saving return address */ -+ /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs, 20 caller-save float regs) * 8 */ -+ /* + 1 for alignment */ -+ addi sp, sp, -0x160 -+ mv s0, sp -+ store ra, 0x8(sp) -+ store s0, 0x0(sp) -+ /* Save allocatable integer registers on the stack, -+ in the order given in proc.ml */ -+ store a0, 0x10(sp) -+ store a1, 0x18(sp) -+ store a2, 0x20(sp) -+ store a3, 0x28(sp) -+ store a4, 0x30(sp) -+ store a5, 0x38(sp) -+ store a6, 0x40(sp) -+ store a7, 0x48(sp) -+ store s2, 0x50(sp) -+ store s3, 0x58(sp) -+ store s4, 0x60(sp) -+ store s5, 0x68(sp) -+ store s6, 0x70(sp) -+ store s7, 0x78(sp) -+ store s8, 0x80(sp) -+ store s9, 0x88(sp) -+ store t2, 0x90(sp) -+ store t3, 0x98(sp) -+ store t4, 0xa0(sp) -+ store t5, 0xa8(sp) -+ store t6, 0xb0(sp) -+ /* Save caller-save floating-point registers on the stack -+ (callee-saves are preserved by caml_garbage_collection) */ -+ fsd ft0, 0xb8(sp) -+ fsd ft1, 0xc0(sp) -+ fsd ft2, 0xc8(sp) -+ fsd ft3, 0xd0(sp) -+ fsd ft4, 0xd8(sp) -+ fsd ft5, 0xe0(sp) -+ fsd ft6, 0xe8(sp) -+ fsd ft7, 0xf0(sp) -+ fsd fa0, 0xf8(sp) -+ fsd fa1, 0x100(sp) -+ fsd fa2, 0x108(sp) -+ fsd fa3, 0x110(sp) -+ fsd fa4, 0x118(sp) -+ fsd fa5, 0x120(sp) -+ fsd fa6, 0x128(sp) -+ fsd fa7, 0x130(sp) -+ fsd ft8, 0x138(sp) -+ fsd ft9, 0x140(sp) -+ fsd ft9, 0x148(sp) -+ fsd ft10, 0x150(sp) -+ fsd ft11, 0x158(sp) -+ /* Store pointer to saved integer registers in caml_gc_regs */ -+ addi TMP1, sp, 16 -+ store TMP1, caml_gc_regs, TMP0 -+ /* Save current allocation pointer for debugging purposes */ -+ store ALLOC_PTR, caml_young_ptr, TMP0 -+ /* Save trap pointer in case an exception is raised during GC */ -+ store TRAP_PTR, caml_exception_pointer, TMP0 -+ /* Call the garbage collector */ -+ call caml_garbage_collection -+ /* Restore registers */ -+ load a0, 0x10(sp) -+ load a1, 0x18(sp) -+ load a2, 0x20(sp) -+ load a3, 0x28(sp) -+ load a4, 0x30(sp) -+ load a5, 0x38(sp) -+ load a6, 0x40(sp) -+ load a7, 0x48(sp) -+ load s2, 0x50(sp) -+ load s3, 0x58(sp) -+ load s4, 0x60(sp) -+ load s5, 0x68(sp) -+ load s6, 0x70(sp) -+ load s7, 0x78(sp) -+ load s8, 0x80(sp) -+ load s9, 0x88(sp) -+ load t2, 0x90(sp) -+ load t3, 0x98(sp) -+ load t4, 0xa0(sp) -+ load t5, 0xa8(sp) -+ load t6, 0xb0(sp) -+ fld ft0, 0xb8(sp) -+ fld ft1, 0xc0(sp) -+ fld ft2, 0xc8(sp) -+ fld ft3, 0xd0(sp) -+ fld ft4, 0xd8(sp) -+ fld ft5, 0xe0(sp) -+ fld ft6, 0xe8(sp) -+ fld ft7, 0xf0(sp) -+ fld fa0, 0xf8(sp) -+ fld fa1, 0x100(sp) -+ fld fa2, 0x108(sp) -+ fld fa3, 0x110(sp) -+ fld fa4, 0x118(sp) -+ fld fa5, 0x120(sp) -+ fld fa6, 0x128(sp) -+ fld fa7, 0x130(sp) -+ fld ft8, 0x138(sp) -+ fld ft9, 0x140(sp) -+ fld ft9, 0x148(sp) -+ fld ft10, 0x150(sp) -+ fld ft11, 0x158(sp) -+ /* Reload new allocation pointer and allocation limit */ -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit -+ /* Free stack space and return to caller */ -+ load ra, 0x8(sp) -+ load s0, 0x0(sp) -+ addi sp, sp, 0x160 -+ ret -+ .size caml_call_gc, .-caml_call_gc -+ -+/* Call a C function from OCaml */ -+/* Function to call is in ARG */ -+ -+ .align 2 -+ .globl caml_c_call -+ .type caml_c_call, @function -+caml_c_call: -+ /* Preserve return address in callee-save register s2 */ -+ mv s2, ra -+ /* Record lowest stack address and return address */ -+ store ra, caml_last_return_address, TMP0 -+ store sp, caml_bottom_of_stack, TMP0 -+ /* Make the exception handler alloc ptr available to the C code */ -+ store ALLOC_PTR, caml_young_ptr, TMP0 -+ store TRAP_PTR, caml_exception_pointer, TMP0 -+ /* Call the function */ -+ jalr ARG -+ /* Reload alloc ptr and alloc limit */ -+ load ALLOC_PTR, caml_young_ptr -+ load TRAP_PTR, caml_exception_pointer -+ /* Return */ -+ jr s2 -+ .size caml_c_call, .-caml_c_call -+ -+/* Raise an exception from OCaml */ -+ .align 2 -+ .globl caml_raise_exn -+ .type caml_raise_exn, @function -+caml_raise_exn: -+ /* Test if backtrace is active */ -+ load TMP1, caml_backtrace_active -+ bnez TMP1, 2f -+1: /* Cut stack at current trap handler */ -+ mv sp, TRAP_PTR -+ /* Pop previous handler and jump to it */ -+ load TMP1, 8(sp) -+ load TRAP_PTR, 0(sp) -+ addi sp, sp, 16 -+ jr TMP1 -+2: /* Preserve exception bucket in callee-save register s2 */ -+ mv s2, a0 -+ /* Stash the backtrace */ -+ mv a1, ra -+ mv a2, sp -+ mv a3, TRAP_PTR -+ call caml_stash_backtrace -+ /* Restore exception bucket and raise */ -+ mv a0, s2 -+ j 1b -+ .size caml_raise_exn, .-caml_raise_exn -+ -+ .globl caml_reraise_exn -+ .type caml_reraise_exn, @function -+ -+/* Raise an exception from C */ -+ -+ .align 2 -+ .globl caml_raise_exception -+ .type caml_raise_exception, @function -+caml_raise_exception: -+ load TRAP_PTR, caml_exception_pointer -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit -+ load TMP1, caml_backtrace_active -+ bnez TMP1, 2f -+1: /* Cut stack at current trap handler */ -+ mv sp, TRAP_PTR -+ load TMP1, 8(sp) -+ load TRAP_PTR, 0(sp) -+ addi sp, sp, 16 -+ jr TMP1 -+2: /* Preserve exception bucket in callee-save register s2 */ -+ mv s2, a0 -+ load a1, caml_last_return_address -+ load a2, caml_bottom_of_stack -+ mv a3, TRAP_PTR -+ call caml_stash_backtrace -+ mv a0, s2 -+ j 1b -+ .size caml_raise_exception, .-caml_raise_exception -+ -+/* Start the OCaml program */ -+ -+ .align 2 -+ .globl caml_start_program -+ .type caml_start_program, @function -+caml_start_program: -+ -+ la ARG, caml_program -+ /* Code shared with caml_callback* */ -+ /* Address of OCaml code to call is in ARG */ -+ /* Arguments to the OCaml code are in a0 ... a7 */ -+.Ljump_to_caml: -+ /* Set up stack frame and save callee-save registers */ -+ addi sp, sp, -0xd0 -+ store ra, 0xc0(sp) -+ store s0, 0x0(sp) -+ store s1, 0x8(sp) -+ store s2, 0x10(sp) -+ store s3, 0x18(sp) -+ store s4, 0x20(sp) -+ store s5, 0x28(sp) -+ store s6, 0x30(sp) -+ store s7, 0x38(sp) -+ store s8, 0x40(sp) -+ store s9, 0x48(sp) -+ store s10, 0x50(sp) -+ store s11, 0x58(sp) -+ fsd fs0, 0x60(sp) -+ fsd fs1, 0x68(sp) -+ fsd fs2, 0x70(sp) -+ fsd fs3, 0x78(sp) -+ fsd fs4, 0x80(sp) -+ fsd fs5, 0x88(sp) -+ fsd fs6, 0x90(sp) -+ fsd fs7, 0x98(sp) -+ fsd fs8, 0xa0(sp) -+ fsd fs9, 0xa8(sp) -+ fsd fs10, 0xb0(sp) -+ fsd fs11, 0xb8(sp) -+ addi sp, sp, -32 -+ /* Setup a callback link on the stack */ -+ load TMP1, caml_bottom_of_stack -+ store TMP1, 0(sp) -+ load TMP1, caml_last_return_address -+ store TMP1, 8(sp) -+ load TMP1, caml_gc_regs -+ store TMP1, 16(sp) -+ /* set up a trap frame */ -+ addi sp, sp, -16 -+ load TMP1, caml_exception_pointer -+ store TMP1, 0(sp) -+ lla TMP0, .Ltrap_handler -+ store TMP0, 8(sp) -+ mv TRAP_PTR, sp -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit -+ store x0, caml_last_return_address, TMP0 -+ jalr ARG -+.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ -+ load TMP1, 0(sp) -+ store TMP1, caml_exception_pointer, TMP0 -+ addi sp, sp, 16 -+.Lreturn_result: /* pop callback link, restoring global variables */ -+ load TMP1, 0(sp) -+ store TMP1, caml_bottom_of_stack, TMP0 -+ load TMP1, 8(sp) -+ store TMP1, caml_last_return_address, TMP0 -+ load TMP1, 16(sp) -+ store TMP1, caml_gc_regs, TMP0 -+ addi sp, sp, 32 -+ /* Update allocation pointer */ -+ store ALLOC_PTR, caml_young_ptr, TMP0 -+ /* reload callee-save registers and return */ -+ load ra, 0xc0(sp) -+ load s0, 0x0(sp) -+ load s1, 0x8(sp) -+ load s2, 0x10(sp) -+ load s3, 0x18(sp) -+ load s4, 0x20(sp) -+ load s5, 0x28(sp) -+ load s6, 0x30(sp) -+ load s7, 0x38(sp) -+ load s8, 0x40(sp) -+ load s9, 0x48(sp) -+ load s10, 0x50(sp) -+ load s11, 0x58(sp) -+ fld fs0, 0x60(sp) -+ fld fs1, 0x68(sp) -+ fld fs2, 0x70(sp) -+ fld fs3, 0x78(sp) -+ fld fs4, 0x80(sp) -+ fld fs5, 0x88(sp) -+ fld fs6, 0x90(sp) -+ fld fs7, 0x98(sp) -+ fld fs8, 0xa0(sp) -+ fld fs9, 0xa8(sp) -+ fld fs10, 0xb0(sp) -+ fld fs11, 0xb8(sp) -+ addi sp, sp, 0xd0 -+ ret -+.Ltrap_handler: -+ store TRAP_PTR, caml_exception_pointer, TMP0 -+ ori a0, a0, 2 -+ j .Lreturn_result -+ .size caml_start_program, .-caml_start_program -+ -+/* Callback from C to OCaml */ -+ -+ .align 2 -+ .globl caml_callback_exn -+ .type caml_callback_exn, @function -+caml_callback_exn: -+ /* Initial shuffling of arguments (a0 = closure, a1 = first arg) */ -+ mv TMP1, a0 -+ mv a0, a1 /* a0 = first arg */ -+ mv a1, TMP1 /* a1 = closure environment */ -+ load ARG, 0(TMP1) /* code pointer */ -+ j .Ljump_to_caml -+ .size caml_callback_exn, .-caml_callback_exn -+ -+ .align 2 -+ .globl caml_callback2_exn -+ .type caml_callback2_exn, @function -+caml_callback2_exn: -+ /* Initial shuffling of arguments (a0 = closure, a1 = arg1, a2 = arg2) */ -+ mv TMP1, a0 -+ mv a0, a1 -+ mv a1, a2 -+ mv a2, TMP1 -+ la ARG, caml_apply2 -+ j .Ljump_to_caml -+ .size caml_callback2_exn, .-caml_callback2_exn -+ -+ .align 2 -+ .globl caml_callback3_exn -+ .type caml_callback3_exn, @function -+caml_callback3_exn: -+ /* Initial shuffling of argumnets */ -+ /* (a0 = closure, a1 = arg1, a2 = arg2, a3 = arg3) */ -+ mv TMP1, a0 -+ mv a0, a1 -+ mv a1, a2 -+ mv a2, a3 -+ mv a3, TMP1 -+ la ARG, caml_apply3 -+ j .Ljump_to_caml -+ .size caml_callback3_exn, .-caml_callback3_exn -+ -+ .align 2 -+ .globl caml_ml_array_bound_error -+ .type caml_ml_array_bound_error, @function -+caml_ml_array_bound_error: -+ /* Load address of [caml_array_bound_error] in ARG */ -+ la ARG, caml_array_bound_error -+ /* Call that function */ -+ j caml_c_call -+ -+ .globl caml_system__code_end -+caml_system__code_end: -+ -+/* GC roots for callback */ -+ -+ .section .data -+ .align 3 -+ .globl caml_system__frametable -+ .type caml_system__frametable, @object -+caml_system__frametable: -+ .quad 1 /* one descriptor */ -+ .quad .Lcaml_retaddr /* return address into callback */ -+ .short -1 /* negative frame size => use callback link */ -+ .short 0 /* no roots */ -+ .align 3 -+ .size caml_system__frametable, .-caml_system__frametable -diff --git a/byterun/caml/stack.h b/byterun/caml/stack.h -index 266863986..e198be0a6 100644 ---- a/byterun/caml/stack.h -+++ b/byterun/caml/stack.h -@@ -70,6 +70,11 @@ - #define Callback_link(sp) ((struct caml_context *)((sp) + 16)) - #endif - -+#ifdef TARGET_riscv /* FIXME FIXME */ -+#define Saved_return_address(sp) *((intnat *)((sp) - 8)) -+#define Callback_link(sp) ((struct caml_context *)((sp) + 16)) -+#endif -+ - /* Structure of OCaml callback contexts */ - - struct caml_context { -diff --git a/config/gnu/config.guess b/config/gnu/config.guess -index b79252d6b..8335398b2 100755 ---- a/config/gnu/config.guess -+++ b/config/gnu/config.guess -@@ -2,7 +2,7 @@ - # Attempt to guess a canonical system name. - # Copyright 1992-2013 Free Software Foundation, Inc. - --timestamp='2013-06-10' -+timestamp='2016-10-23' - - # This file is free software; you can redistribute it and/or modify it - # under the terms of the GNU General Public License as published by -@@ -1001,6 +1001,9 @@ EOF - ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} - exit ;; -+ riscv*:Linux:*:*) -+ echo ${UNAME_MACHINE}-unknown-linux -+ exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} - exit ;; -diff --git a/configure b/configure -index 53f45f85b..cf5a4a02a 100755 ---- a/configure -+++ b/configure -@@ -928,6 +928,7 @@ if $with_sharedlibs; then - arm*-*-freebsd*) natdynlink=true;; - earm*-*-netbsd*) natdynlink=true;; - aarch64-*-linux*) natdynlink=true;; -+ riscv*-*-linux*) natdynlink=true;; - esac - fi - -@@ -1004,6 +1005,8 @@ case "$target" in - x86_64-*-mingw*) arch=amd64; system=mingw;; - aarch64-*-linux*) arch=arm64; system=linux;; - x86_64-*-cygwin*) arch=amd64; system=cygwin;; -+ riscv32-*-linux*) arch=riscv; model=riscv32; system=linux;; -+ riscv64-*-linux*) arch=riscv; model=riscv64; system=linux;; - esac - - # Some platforms exist both in 32-bit and 64-bit variants, not distinguished -@@ -1062,7 +1065,7 @@ case "$arch,$system" in - aspp="${TOOLPREF}cc -c";; - *,freebsd) as="${TOOLPREF}as" - aspp="${TOOLPREF}cc -c";; -- amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd) -+ amd64,*|arm,*|arm64,*|i386,*|power,bsd*|power,netbsd|riscv,*) - as="${TOOLPREF}as" - case "$ccfamily" in - clang-*) --- -2.17.1 - diff --git a/0005-Copyright-untabify.patch b/0005-Copyright-untabify.patch deleted file mode 100644 index da7749a..0000000 --- a/0005-Copyright-untabify.patch +++ /dev/null @@ -1,717 +0,0 @@ -From 2e4038b6b8073f55012613f18cb19a4c99e8219d Mon Sep 17 00:00:00 2001 -From: Nicolas Ojeda Bar -Date: Fri, 1 Dec 2017 14:39:46 +0100 -Subject: [PATCH 5/8] Copyright, untabify - ---- - asmrun/riscv.S | 608 ++++++++++++++++++++++++------------------------- - 1 file changed, 304 insertions(+), 304 deletions(-) - -diff --git a/asmrun/riscv.S b/asmrun/riscv.S -index a82048efc..88d7ab924 100644 ---- a/asmrun/riscv.S -+++ b/asmrun/riscv.S -@@ -4,7 +4,7 @@ - /* */ - /* Nicolas Ojeda Bar */ - /* */ --/* Copyright 1996 Institut National de Recherche en Informatique et */ -+/* Copyright 2017 Institut National de Recherche en Informatique et */ - /* en Automatique. All rights reserved. This file is distributed */ - /* under the terms of the GNU Library General Public License, with */ - /* the special exception on linking described in file ../LICENSE. */ -@@ -37,388 +37,388 @@ - .option nopic - #endif - -- .section .text -+ .section .text - /* Invoke the garbage collector. */ - -- .globl caml_system__code_begin -+ .globl caml_system__code_begin - caml_system__code_begin: - -- .align 2 -- .globl caml_call_gc -- .type caml_call_gc, @function -+ .align 2 -+ .globl caml_call_gc -+ .type caml_call_gc, @function - caml_call_gc: - /* Record return address */ -- store ra, caml_last_return_address, TMP0 -+ store ra, caml_last_return_address, TMP0 - /* Record lowest stack address */ -- mv TMP1, sp -- store sp, caml_bottom_of_stack, TMP0 -+ mv TMP1, sp -+ store sp, caml_bottom_of_stack, TMP0 - .Lcaml_call_gc: -- /* Set up stack space, saving return address */ -+ /* Set up stack space, saving return address */ - /* (1 reg for RA, 1 reg for FP, 21 allocatable int regs, 20 caller-save float regs) * 8 */ - /* + 1 for alignment */ -- addi sp, sp, -0x160 -- mv s0, sp -- store ra, 0x8(sp) -- store s0, 0x0(sp) -+ addi sp, sp, -0x160 -+ mv s0, sp -+ store ra, 0x8(sp) -+ store s0, 0x0(sp) - /* Save allocatable integer registers on the stack, - in the order given in proc.ml */ -- store a0, 0x10(sp) -- store a1, 0x18(sp) -- store a2, 0x20(sp) -- store a3, 0x28(sp) -- store a4, 0x30(sp) -- store a5, 0x38(sp) -- store a6, 0x40(sp) -- store a7, 0x48(sp) -- store s2, 0x50(sp) -- store s3, 0x58(sp) -- store s4, 0x60(sp) -- store s5, 0x68(sp) -- store s6, 0x70(sp) -- store s7, 0x78(sp) -- store s8, 0x80(sp) -- store s9, 0x88(sp) -- store t2, 0x90(sp) -- store t3, 0x98(sp) -- store t4, 0xa0(sp) -- store t5, 0xa8(sp) -- store t6, 0xb0(sp) -+ store a0, 0x10(sp) -+ store a1, 0x18(sp) -+ store a2, 0x20(sp) -+ store a3, 0x28(sp) -+ store a4, 0x30(sp) -+ store a5, 0x38(sp) -+ store a6, 0x40(sp) -+ store a7, 0x48(sp) -+ store s2, 0x50(sp) -+ store s3, 0x58(sp) -+ store s4, 0x60(sp) -+ store s5, 0x68(sp) -+ store s6, 0x70(sp) -+ store s7, 0x78(sp) -+ store s8, 0x80(sp) -+ store s9, 0x88(sp) -+ store t2, 0x90(sp) -+ store t3, 0x98(sp) -+ store t4, 0xa0(sp) -+ store t5, 0xa8(sp) -+ store t6, 0xb0(sp) - /* Save caller-save floating-point registers on the stack - (callee-saves are preserved by caml_garbage_collection) */ -- fsd ft0, 0xb8(sp) -- fsd ft1, 0xc0(sp) -- fsd ft2, 0xc8(sp) -- fsd ft3, 0xd0(sp) -- fsd ft4, 0xd8(sp) -- fsd ft5, 0xe0(sp) -- fsd ft6, 0xe8(sp) -- fsd ft7, 0xf0(sp) -- fsd fa0, 0xf8(sp) -- fsd fa1, 0x100(sp) -- fsd fa2, 0x108(sp) -- fsd fa3, 0x110(sp) -- fsd fa4, 0x118(sp) -- fsd fa5, 0x120(sp) -- fsd fa6, 0x128(sp) -- fsd fa7, 0x130(sp) -- fsd ft8, 0x138(sp) -- fsd ft9, 0x140(sp) -- fsd ft9, 0x148(sp) -- fsd ft10, 0x150(sp) -- fsd ft11, 0x158(sp) -+ fsd ft0, 0xb8(sp) -+ fsd ft1, 0xc0(sp) -+ fsd ft2, 0xc8(sp) -+ fsd ft3, 0xd0(sp) -+ fsd ft4, 0xd8(sp) -+ fsd ft5, 0xe0(sp) -+ fsd ft6, 0xe8(sp) -+ fsd ft7, 0xf0(sp) -+ fsd fa0, 0xf8(sp) -+ fsd fa1, 0x100(sp) -+ fsd fa2, 0x108(sp) -+ fsd fa3, 0x110(sp) -+ fsd fa4, 0x118(sp) -+ fsd fa5, 0x120(sp) -+ fsd fa6, 0x128(sp) -+ fsd fa7, 0x130(sp) -+ fsd ft8, 0x138(sp) -+ fsd ft9, 0x140(sp) -+ fsd ft9, 0x148(sp) -+ fsd ft10, 0x150(sp) -+ fsd ft11, 0x158(sp) - /* Store pointer to saved integer registers in caml_gc_regs */ -- addi TMP1, sp, 16 -- store TMP1, caml_gc_regs, TMP0 -+ addi TMP1, sp, 16 -+ store TMP1, caml_gc_regs, TMP0 - /* Save current allocation pointer for debugging purposes */ -- store ALLOC_PTR, caml_young_ptr, TMP0 -+ store ALLOC_PTR, caml_young_ptr, TMP0 - /* Save trap pointer in case an exception is raised during GC */ -- store TRAP_PTR, caml_exception_pointer, TMP0 -+ store TRAP_PTR, caml_exception_pointer, TMP0 - /* Call the garbage collector */ -- call caml_garbage_collection -+ call caml_garbage_collection - /* Restore registers */ -- load a0, 0x10(sp) -- load a1, 0x18(sp) -- load a2, 0x20(sp) -- load a3, 0x28(sp) -- load a4, 0x30(sp) -- load a5, 0x38(sp) -- load a6, 0x40(sp) -- load a7, 0x48(sp) -- load s2, 0x50(sp) -- load s3, 0x58(sp) -- load s4, 0x60(sp) -- load s5, 0x68(sp) -- load s6, 0x70(sp) -- load s7, 0x78(sp) -- load s8, 0x80(sp) -- load s9, 0x88(sp) -- load t2, 0x90(sp) -- load t3, 0x98(sp) -- load t4, 0xa0(sp) -- load t5, 0xa8(sp) -- load t6, 0xb0(sp) -- fld ft0, 0xb8(sp) -- fld ft1, 0xc0(sp) -- fld ft2, 0xc8(sp) -- fld ft3, 0xd0(sp) -- fld ft4, 0xd8(sp) -- fld ft5, 0xe0(sp) -- fld ft6, 0xe8(sp) -- fld ft7, 0xf0(sp) -- fld fa0, 0xf8(sp) -- fld fa1, 0x100(sp) -- fld fa2, 0x108(sp) -- fld fa3, 0x110(sp) -- fld fa4, 0x118(sp) -- fld fa5, 0x120(sp) -- fld fa6, 0x128(sp) -- fld fa7, 0x130(sp) -- fld ft8, 0x138(sp) -- fld ft9, 0x140(sp) -- fld ft9, 0x148(sp) -- fld ft10, 0x150(sp) -- fld ft11, 0x158(sp) -+ load a0, 0x10(sp) -+ load a1, 0x18(sp) -+ load a2, 0x20(sp) -+ load a3, 0x28(sp) -+ load a4, 0x30(sp) -+ load a5, 0x38(sp) -+ load a6, 0x40(sp) -+ load a7, 0x48(sp) -+ load s2, 0x50(sp) -+ load s3, 0x58(sp) -+ load s4, 0x60(sp) -+ load s5, 0x68(sp) -+ load s6, 0x70(sp) -+ load s7, 0x78(sp) -+ load s8, 0x80(sp) -+ load s9, 0x88(sp) -+ load t2, 0x90(sp) -+ load t3, 0x98(sp) -+ load t4, 0xa0(sp) -+ load t5, 0xa8(sp) -+ load t6, 0xb0(sp) -+ fld ft0, 0xb8(sp) -+ fld ft1, 0xc0(sp) -+ fld ft2, 0xc8(sp) -+ fld ft3, 0xd0(sp) -+ fld ft4, 0xd8(sp) -+ fld ft5, 0xe0(sp) -+ fld ft6, 0xe8(sp) -+ fld ft7, 0xf0(sp) -+ fld fa0, 0xf8(sp) -+ fld fa1, 0x100(sp) -+ fld fa2, 0x108(sp) -+ fld fa3, 0x110(sp) -+ fld fa4, 0x118(sp) -+ fld fa5, 0x120(sp) -+ fld fa6, 0x128(sp) -+ fld fa7, 0x130(sp) -+ fld ft8, 0x138(sp) -+ fld ft9, 0x140(sp) -+ fld ft9, 0x148(sp) -+ fld ft10, 0x150(sp) -+ fld ft11, 0x158(sp) - /* Reload new allocation pointer and allocation limit */ -- load ALLOC_PTR, caml_young_ptr -- load ALLOC_LIMIT, caml_young_limit -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit - /* Free stack space and return to caller */ -- load ra, 0x8(sp) -- load s0, 0x0(sp) -- addi sp, sp, 0x160 -+ load ra, 0x8(sp) -+ load s0, 0x0(sp) -+ addi sp, sp, 0x160 - ret -- .size caml_call_gc, .-caml_call_gc -+ .size caml_call_gc, .-caml_call_gc - - /* Call a C function from OCaml */ - /* Function to call is in ARG */ - -- .align 2 -- .globl caml_c_call -- .type caml_c_call, @function -+ .align 2 -+ .globl caml_c_call -+ .type caml_c_call, @function - caml_c_call: - /* Preserve return address in callee-save register s2 */ -- mv s2, ra -+ mv s2, ra - /* Record lowest stack address and return address */ -- store ra, caml_last_return_address, TMP0 -- store sp, caml_bottom_of_stack, TMP0 -+ store ra, caml_last_return_address, TMP0 -+ store sp, caml_bottom_of_stack, TMP0 - /* Make the exception handler alloc ptr available to the C code */ -- store ALLOC_PTR, caml_young_ptr, TMP0 -- store TRAP_PTR, caml_exception_pointer, TMP0 -+ store ALLOC_PTR, caml_young_ptr, TMP0 -+ store TRAP_PTR, caml_exception_pointer, TMP0 - /* Call the function */ -- jalr ARG -+ jalr ARG - /* Reload alloc ptr and alloc limit */ -- load ALLOC_PTR, caml_young_ptr -- load TRAP_PTR, caml_exception_pointer -+ load ALLOC_PTR, caml_young_ptr -+ load TRAP_PTR, caml_exception_pointer - /* Return */ -- jr s2 -- .size caml_c_call, .-caml_c_call -+ jr s2 -+ .size caml_c_call, .-caml_c_call - - /* Raise an exception from OCaml */ -- .align 2 -- .globl caml_raise_exn -- .type caml_raise_exn, @function -+ .align 2 -+ .globl caml_raise_exn -+ .type caml_raise_exn, @function - caml_raise_exn: - /* Test if backtrace is active */ -- load TMP1, caml_backtrace_active -- bnez TMP1, 2f -+ load TMP1, caml_backtrace_active -+ bnez TMP1, 2f - 1: /* Cut stack at current trap handler */ -- mv sp, TRAP_PTR -+ mv sp, TRAP_PTR - /* Pop previous handler and jump to it */ -- load TMP1, 8(sp) -- load TRAP_PTR, 0(sp) -- addi sp, sp, 16 -- jr TMP1 -+ load TMP1, 8(sp) -+ load TRAP_PTR, 0(sp) -+ addi sp, sp, 16 -+ jr TMP1 - 2: /* Preserve exception bucket in callee-save register s2 */ -- mv s2, a0 -+ mv s2, a0 - /* Stash the backtrace */ -- mv a1, ra -- mv a2, sp -- mv a3, TRAP_PTR -- call caml_stash_backtrace -+ mv a1, ra -+ mv a2, sp -+ mv a3, TRAP_PTR -+ call caml_stash_backtrace - /* Restore exception bucket and raise */ -- mv a0, s2 -- j 1b -- .size caml_raise_exn, .-caml_raise_exn -+ mv a0, s2 -+ j 1b -+ .size caml_raise_exn, .-caml_raise_exn - -- .globl caml_reraise_exn -- .type caml_reraise_exn, @function -+ .globl caml_reraise_exn -+ .type caml_reraise_exn, @function - - /* Raise an exception from C */ - -- .align 2 -- .globl caml_raise_exception -- .type caml_raise_exception, @function -+ .align 2 -+ .globl caml_raise_exception -+ .type caml_raise_exception, @function - caml_raise_exception: -- load TRAP_PTR, caml_exception_pointer -- load ALLOC_PTR, caml_young_ptr -- load ALLOC_LIMIT, caml_young_limit -- load TMP1, caml_backtrace_active -- bnez TMP1, 2f -+ load TRAP_PTR, caml_exception_pointer -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit -+ load TMP1, caml_backtrace_active -+ bnez TMP1, 2f - 1: /* Cut stack at current trap handler */ -- mv sp, TRAP_PTR -- load TMP1, 8(sp) -- load TRAP_PTR, 0(sp) -- addi sp, sp, 16 -- jr TMP1 -+ mv sp, TRAP_PTR -+ load TMP1, 8(sp) -+ load TRAP_PTR, 0(sp) -+ addi sp, sp, 16 -+ jr TMP1 - 2: /* Preserve exception bucket in callee-save register s2 */ -- mv s2, a0 -- load a1, caml_last_return_address -- load a2, caml_bottom_of_stack -- mv a3, TRAP_PTR -- call caml_stash_backtrace -- mv a0, s2 -- j 1b -- .size caml_raise_exception, .-caml_raise_exception -+ mv s2, a0 -+ load a1, caml_last_return_address -+ load a2, caml_bottom_of_stack -+ mv a3, TRAP_PTR -+ call caml_stash_backtrace -+ mv a0, s2 -+ j 1b -+ .size caml_raise_exception, .-caml_raise_exception - - /* Start the OCaml program */ - -- .align 2 -- .globl caml_start_program -- .type caml_start_program, @function -+ .align 2 -+ .globl caml_start_program -+ .type caml_start_program, @function - caml_start_program: - -- la ARG, caml_program -+ la ARG, caml_program - /* Code shared with caml_callback* */ - /* Address of OCaml code to call is in ARG */ - /* Arguments to the OCaml code are in a0 ... a7 */ - .Ljump_to_caml: -- /* Set up stack frame and save callee-save registers */ -- addi sp, sp, -0xd0 -- store ra, 0xc0(sp) -- store s0, 0x0(sp) -- store s1, 0x8(sp) -- store s2, 0x10(sp) -- store s3, 0x18(sp) -- store s4, 0x20(sp) -- store s5, 0x28(sp) -- store s6, 0x30(sp) -- store s7, 0x38(sp) -- store s8, 0x40(sp) -- store s9, 0x48(sp) -- store s10, 0x50(sp) -- store s11, 0x58(sp) -- fsd fs0, 0x60(sp) -- fsd fs1, 0x68(sp) -- fsd fs2, 0x70(sp) -- fsd fs3, 0x78(sp) -- fsd fs4, 0x80(sp) -- fsd fs5, 0x88(sp) -- fsd fs6, 0x90(sp) -- fsd fs7, 0x98(sp) -- fsd fs8, 0xa0(sp) -- fsd fs9, 0xa8(sp) -- fsd fs10, 0xb0(sp) -- fsd fs11, 0xb8(sp) -- addi sp, sp, -32 -+ /* Set up stack frame and save callee-save registers */ -+ addi sp, sp, -0xd0 -+ store ra, 0xc0(sp) -+ store s0, 0x0(sp) -+ store s1, 0x8(sp) -+ store s2, 0x10(sp) -+ store s3, 0x18(sp) -+ store s4, 0x20(sp) -+ store s5, 0x28(sp) -+ store s6, 0x30(sp) -+ store s7, 0x38(sp) -+ store s8, 0x40(sp) -+ store s9, 0x48(sp) -+ store s10, 0x50(sp) -+ store s11, 0x58(sp) -+ fsd fs0, 0x60(sp) -+ fsd fs1, 0x68(sp) -+ fsd fs2, 0x70(sp) -+ fsd fs3, 0x78(sp) -+ fsd fs4, 0x80(sp) -+ fsd fs5, 0x88(sp) -+ fsd fs6, 0x90(sp) -+ fsd fs7, 0x98(sp) -+ fsd fs8, 0xa0(sp) -+ fsd fs9, 0xa8(sp) -+ fsd fs10, 0xb0(sp) -+ fsd fs11, 0xb8(sp) -+ addi sp, sp, -32 - /* Setup a callback link on the stack */ -- load TMP1, caml_bottom_of_stack -- store TMP1, 0(sp) -- load TMP1, caml_last_return_address -- store TMP1, 8(sp) -- load TMP1, caml_gc_regs -- store TMP1, 16(sp) -- /* set up a trap frame */ -- addi sp, sp, -16 -- load TMP1, caml_exception_pointer -- store TMP1, 0(sp) -- lla TMP0, .Ltrap_handler -- store TMP0, 8(sp) -- mv TRAP_PTR, sp -- load ALLOC_PTR, caml_young_ptr -- load ALLOC_LIMIT, caml_young_limit -- store x0, caml_last_return_address, TMP0 -- jalr ARG --.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ -- load TMP1, 0(sp) -- store TMP1, caml_exception_pointer, TMP0 -- addi sp, sp, 16 --.Lreturn_result: /* pop callback link, restoring global variables */ -- load TMP1, 0(sp) -- store TMP1, caml_bottom_of_stack, TMP0 -- load TMP1, 8(sp) -- store TMP1, caml_last_return_address, TMP0 -- load TMP1, 16(sp) -- store TMP1, caml_gc_regs, TMP0 -- addi sp, sp, 32 -- /* Update allocation pointer */ -- store ALLOC_PTR, caml_young_ptr, TMP0 -- /* reload callee-save registers and return */ -- load ra, 0xc0(sp) -- load s0, 0x0(sp) -- load s1, 0x8(sp) -- load s2, 0x10(sp) -- load s3, 0x18(sp) -- load s4, 0x20(sp) -- load s5, 0x28(sp) -- load s6, 0x30(sp) -- load s7, 0x38(sp) -- load s8, 0x40(sp) -- load s9, 0x48(sp) -- load s10, 0x50(sp) -- load s11, 0x58(sp) -- fld fs0, 0x60(sp) -- fld fs1, 0x68(sp) -- fld fs2, 0x70(sp) -- fld fs3, 0x78(sp) -- fld fs4, 0x80(sp) -- fld fs5, 0x88(sp) -- fld fs6, 0x90(sp) -- fld fs7, 0x98(sp) -- fld fs8, 0xa0(sp) -- fld fs9, 0xa8(sp) -- fld fs10, 0xb0(sp) -- fld fs11, 0xb8(sp) -- addi sp, sp, 0xd0 -- ret -+ load TMP1, caml_bottom_of_stack -+ store TMP1, 0(sp) -+ load TMP1, caml_last_return_address -+ store TMP1, 8(sp) -+ load TMP1, caml_gc_regs -+ store TMP1, 16(sp) -+ /* set up a trap frame */ -+ addi sp, sp, -16 -+ load TMP1, caml_exception_pointer -+ store TMP1, 0(sp) -+ lla TMP0, .Ltrap_handler -+ store TMP0, 8(sp) -+ mv TRAP_PTR, sp -+ load ALLOC_PTR, caml_young_ptr -+ load ALLOC_LIMIT, caml_young_limit -+ store x0, caml_last_return_address, TMP0 -+ jalr ARG -+.Lcaml_retaddr: /* pop trap frame, restoring caml_exception_pointer */ -+ load TMP1, 0(sp) -+ store TMP1, caml_exception_pointer, TMP0 -+ addi sp, sp, 16 -+.Lreturn_result: /* pop callback link, restoring global variables */ -+ load TMP1, 0(sp) -+ store TMP1, caml_bottom_of_stack, TMP0 -+ load TMP1, 8(sp) -+ store TMP1, caml_last_return_address, TMP0 -+ load TMP1, 16(sp) -+ store TMP1, caml_gc_regs, TMP0 -+ addi sp, sp, 32 -+ /* Update allocation pointer */ -+ store ALLOC_PTR, caml_young_ptr, TMP0 -+ /* reload callee-save registers and return */ -+ load ra, 0xc0(sp) -+ load s0, 0x0(sp) -+ load s1, 0x8(sp) -+ load s2, 0x10(sp) -+ load s3, 0x18(sp) -+ load s4, 0x20(sp) -+ load s5, 0x28(sp) -+ load s6, 0x30(sp) -+ load s7, 0x38(sp) -+ load s8, 0x40(sp) -+ load s9, 0x48(sp) -+ load s10, 0x50(sp) -+ load s11, 0x58(sp) -+ fld fs0, 0x60(sp) -+ fld fs1, 0x68(sp) -+ fld fs2, 0x70(sp) -+ fld fs3, 0x78(sp) -+ fld fs4, 0x80(sp) -+ fld fs5, 0x88(sp) -+ fld fs6, 0x90(sp) -+ fld fs7, 0x98(sp) -+ fld fs8, 0xa0(sp) -+ fld fs9, 0xa8(sp) -+ fld fs10, 0xb0(sp) -+ fld fs11, 0xb8(sp) -+ addi sp, sp, 0xd0 -+ ret - .Ltrap_handler: -- store TRAP_PTR, caml_exception_pointer, TMP0 -- ori a0, a0, 2 -- j .Lreturn_result -- .size caml_start_program, .-caml_start_program -+ store TRAP_PTR, caml_exception_pointer, TMP0 -+ ori a0, a0, 2 -+ j .Lreturn_result -+ .size caml_start_program, .-caml_start_program - - /* Callback from C to OCaml */ - -- .align 2 -- .globl caml_callback_exn -- .type caml_callback_exn, @function -+ .align 2 -+ .globl caml_callback_exn -+ .type caml_callback_exn, @function - caml_callback_exn: - /* Initial shuffling of arguments (a0 = closure, a1 = first arg) */ -- mv TMP1, a0 -- mv a0, a1 /* a0 = first arg */ -- mv a1, TMP1 /* a1 = closure environment */ -- load ARG, 0(TMP1) /* code pointer */ -- j .Ljump_to_caml -- .size caml_callback_exn, .-caml_callback_exn -+ mv TMP1, a0 -+ mv a0, a1 /* a0 = first arg */ -+ mv a1, TMP1 /* a1 = closure environment */ -+ load ARG, 0(TMP1) /* code pointer */ -+ j .Ljump_to_caml -+ .size caml_callback_exn, .-caml_callback_exn - -- .align 2 -- .globl caml_callback2_exn -- .type caml_callback2_exn, @function -+ .align 2 -+ .globl caml_callback2_exn -+ .type caml_callback2_exn, @function - caml_callback2_exn: - /* Initial shuffling of arguments (a0 = closure, a1 = arg1, a2 = arg2) */ -- mv TMP1, a0 -- mv a0, a1 -- mv a1, a2 -- mv a2, TMP1 -- la ARG, caml_apply2 -- j .Ljump_to_caml -- .size caml_callback2_exn, .-caml_callback2_exn -+ mv TMP1, a0 -+ mv a0, a1 -+ mv a1, a2 -+ mv a2, TMP1 -+ la ARG, caml_apply2 -+ j .Ljump_to_caml -+ .size caml_callback2_exn, .-caml_callback2_exn - -- .align 2 -- .globl caml_callback3_exn -- .type caml_callback3_exn, @function -+ .align 2 -+ .globl caml_callback3_exn -+ .type caml_callback3_exn, @function - caml_callback3_exn: - /* Initial shuffling of argumnets */ - /* (a0 = closure, a1 = arg1, a2 = arg2, a3 = arg3) */ -- mv TMP1, a0 -- mv a0, a1 -- mv a1, a2 -- mv a2, a3 -- mv a3, TMP1 -- la ARG, caml_apply3 -- j .Ljump_to_caml -- .size caml_callback3_exn, .-caml_callback3_exn -+ mv TMP1, a0 -+ mv a0, a1 -+ mv a1, a2 -+ mv a2, a3 -+ mv a3, TMP1 -+ la ARG, caml_apply3 -+ j .Ljump_to_caml -+ .size caml_callback3_exn, .-caml_callback3_exn - -- .align 2 -- .globl caml_ml_array_bound_error -- .type caml_ml_array_bound_error, @function -+ .align 2 -+ .globl caml_ml_array_bound_error -+ .type caml_ml_array_bound_error, @function - caml_ml_array_bound_error: - /* Load address of [caml_array_bound_error] in ARG */ -- la ARG, caml_array_bound_error -+ la ARG, caml_array_bound_error - /* Call that function */ -- j caml_c_call -+ j caml_c_call - -- .globl caml_system__code_end -+ .globl caml_system__code_end - caml_system__code_end: - - /* GC roots for callback */ - -- .section .data -- .align 3 -- .globl caml_system__frametable -- .type caml_system__frametable, @object -+ .section .data -+ .align 3 -+ .globl caml_system__frametable -+ .type caml_system__frametable, @object - caml_system__frametable: -- .quad 1 /* one descriptor */ -- .quad .Lcaml_retaddr /* return address into callback */ -- .short -1 /* negative frame size => use callback link */ -- .short 0 /* no roots */ -- .align 3 -- .size caml_system__frametable, .-caml_system__frametable -+ .quad 1 /* one descriptor */ -+ .quad .Lcaml_retaddr /* return address into callback */ -+ .short -1 /* negative frame size => use callback link */ -+ .short 0 /* no roots */ -+ .align 3 -+ .size caml_system__frametable, .-caml_system__frametable --- -2.17.1 - diff --git a/0006-fix-caml_c_call-reload-caml_young_limit.patch b/0006-fix-caml_c_call-reload-caml_young_limit.patch deleted file mode 100644 index a41c53c..0000000 --- a/0006-fix-caml_c_call-reload-caml_young_limit.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 207fbbc2616ee44e048dd5bb133e52f252cd1caf Mon Sep 17 00:00:00 2001 -From: Nicolas Ojeda Bar -Date: Sat, 2 Dec 2017 10:44:41 +0100 -Subject: [PATCH 6/8] fix caml_c_call: reload caml_young_limit - ---- - asmrun/riscv.S | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/asmrun/riscv.S b/asmrun/riscv.S -index 88d7ab924..121f8ba71 100644 ---- a/asmrun/riscv.S -+++ b/asmrun/riscv.S -@@ -187,7 +187,7 @@ caml_c_call: - jalr ARG - /* Reload alloc ptr and alloc limit */ - load ALLOC_PTR, caml_young_ptr -- load TRAP_PTR, caml_exception_pointer -+ load ALLOC_LIMIT, caml_young_limit - /* Return */ - jr s2 - .size caml_c_call, .-caml_c_call --- -2.17.1 - diff --git a/0007-Adapt-to-4.07.patch b/0007-Adapt-to-4.07.patch deleted file mode 100644 index 0cda82d..0000000 --- a/0007-Adapt-to-4.07.patch +++ /dev/null @@ -1,67 +0,0 @@ -From a89427d52a20633be40056fe008b7eeec5ded7dd Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Nicol=C3=A1s=20Ojeda=20B=C3=A4r?= -Date: Tue, 15 May 2018 07:17:06 +0000 -Subject: [PATCH 7/8] Adapt to 4.07 - ---- - asmcomp/riscv/emit.mlp | 28 +++++++++++++++++----------- - asmcomp/riscv/selection.ml | 2 +- - 2 files changed, 18 insertions(+), 12 deletions(-) - -diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp -index 51165d0f1..718dca080 100644 ---- a/asmcomp/riscv/emit.mlp -+++ b/asmcomp/riscv/emit.mlp -@@ -461,19 +461,25 @@ let emit_instr i = - ` {emit_string name} {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}, {emit_label lbl}\n` - | Iinttest_imm _ -> - fatal_error "Emit.emit_instr (Iinttest_imm _)" -- | Ifloattest(cmp, neg) -> -- let neg = match cmp with -- | Ceq -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -- | Cne -> ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; not neg -- | Clt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -- | Cgt -> ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg -- | Cle -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n`; neg -- | Cge -> ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n`; neg -- in -- if neg then -+ | Ifloattest cmp -> -+ begin match cmp with -+ | CFeq | CFneq -> -+ ` feq.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | CFlt | CFnlt -> -+ ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | CFgt | CFngt -> -+ ` flt.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` -+ | CFle | CFnle -> -+ ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, {emit_reg i.arg.(1)}\n` -+ | CFge | CFnge -> -+ ` fle.d {emit_reg reg_tmp1}, {emit_reg i.arg.(1)}, {emit_reg i.arg.(0)}\n` -+ end; -+ begin match cmp with -+ | CFneq | CFnlt | CFngt | CFnle | CFnge -> - ` beqz {emit_reg reg_tmp1}, {emit_label lbl}\n` -- else -+ | CFeq | CFlt | CFgt | CFle | CFge -> - ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` -+ end - | Ioddtest -> - ` andi {emit_reg reg_tmp1}, {emit_reg i.arg.(0)}, 1\n`; - ` bnez {emit_reg reg_tmp1}, {emit_label lbl}\n` -diff --git a/asmcomp/riscv/selection.ml b/asmcomp/riscv/selection.ml -index 092ca88aa..1f0af6abc 100644 ---- a/asmcomp/riscv/selection.ml -+++ b/asmcomp/riscv/selection.ml -@@ -61,7 +61,7 @@ method! select_condition = function - | Cop(Ccmpa cmp, args, _) -> - (Iinttest(Iunsigned cmp), Ctuple args) - | Cop(Ccmpf cmp, args, _) -> -- (Ifloattest(cmp, false), Ctuple args) -+ (Ifloattest cmp, Ctuple args) - | Cop(Cand, [arg; Cconst_int 1], _) -> - (Ioddtest, arg) - | arg -> --- -2.17.1 - diff --git a/0008-riscv-Emit-debug-info.patch b/0008-riscv-Emit-debug-info.patch deleted file mode 100644 index 6d72833..0000000 --- a/0008-riscv-Emit-debug-info.patch +++ /dev/null @@ -1,40 +0,0 @@ -From af276d83f41cb9eb9f1e50a75a9be205c9b2fee6 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Tue, 5 Jun 2018 19:48:08 +0000 -Subject: [PATCH 8/8] riscv: Emit debug info. - ---- - asmcomp/riscv/emit.mlp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/asmcomp/riscv/emit.mlp b/asmcomp/riscv/emit.mlp -index 718dca080..e42ee9770 100644 ---- a/asmcomp/riscv/emit.mlp -+++ b/asmcomp/riscv/emit.mlp -@@ -261,6 +261,7 @@ let tailrec_entry_point = ref 0 - (* Output the assembly code for an instruction *) - - let emit_instr i = -+ emit_debug_info i.dbg; - match i.desc with - Lend -> () - | Lop(Imove | Ispill | Ireload) -> -@@ -560,6 +561,7 @@ let fundecl fundecl = - emit_stack_adjustment (-n); - if !contains_calls then store_ra n; - `{emit_label !tailrec_entry_point}:\n`; -+ emit_debug_info fundecl.fun_dbg; - emit_all fundecl.fun_body; - List.iter emit_call_gc !call_gc_sites; - List.iter emit_call_bound_error !bound_error_sites; -@@ -619,6 +621,7 @@ let data l = - - let begin_assembly() = - ` .file \"\"\n`; (* PR#7073 *) -+ reset_debug_info (); - (* Emit the beginning of the segments *) - let lbl_begin = Compilenv.make_symbol (Some "data_begin") in - ` {emit_string data_space}\n`; --- -2.17.1 - diff --git a/gating.yaml b/gating.yaml new file mode 100755 index 0000000..2c7ed80 --- /dev/null +++ b/gating.yaml @@ -0,0 +1,6 @@ +--- !Policy +product_versions: + - rhel-* +decision_context: osci_compose_gate +rules: + - !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional} diff --git a/macros.ocaml-rpm b/macros.ocaml-rpm new file mode 100644 index 0000000..ac94c48 --- /dev/null +++ b/macros.ocaml-rpm @@ -0,0 +1,69 @@ +# Make %files lists from an installed tree of files. +# Options: +# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, +# is placed in its own package. This option requires the existence of opam +# *.install files in the build tree. +# -n: suppress creation of a devel subpackage. +%ocaml_files(sn) %{python3} /usr/lib/rpm/redhat/ocaml_files.py %{-s} %{-n} %{buildroot} %{ocamldir} + +# Internal macro holding the common parts of ocaml_install and dune_install +%ocaml_install_common(sn) %{expand: +rm -rf %{buildroot}%{_prefix}/doc +mlis=$(find %{buildroot}%{_libdir}/ocaml -name '*.mli') +rm -f ${mlis//.mli/.ml} +%ocaml_files %{-s} %{-n}} + +# Install files listed in opam *.install files. +# Options: +# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, +# is placed in its own package. +# -n: suppress creation of a devel subpackage. +%ocaml_install(sn) %{expand: +%{python3} /usr/lib/rpm/redhat/ocaml_files.py -i %{-s} %{-n} %{buildroot} %{ocamldir} +%ocaml_install_common %{-s} %{-n}} + +# Add smp_mflags to arguments if no -j release option is given. +# Add --release to arguments if no -p or --release option is given. +# Add --verbose to arguments if it is not given. +%dune_add_flags(-) %{lua: + has_j = false + has_p = false + has_v = false + for _, flag in pairs(arg) do + if flag:find("^-j") then + has_j = true + elseif flag:find("^-p") or flag:find("^--release)") then + has_p = true + elseif flag:find("^--verbose") then + has_v = true + end + end + if not has_j then + table.insert(arg, 1, rpm.expand("%{?_smp_mflags}")) + end + if not has_p then + table.insert(arg, 1, "--release") + end + if not has_v then + table.insert(arg, 1, "--verbose") + end + print(table.concat(arg, " ")) +} + +# Build with dune +%dune_build(-) dune build %{dune_add_flags %*} + +# Run tests with dune +%dune_check(-) dune runtest %{dune_add_flags %*} + +# Install with dune +# Options: +# -s: separate packaging; every subdirectory of %%{ocamldir}, except stublibs, +# is placed in its own package. +# -n: suppress creation of a devel subpackage. +%dune_install(sn) %{expand: +dune install --destdir=%{buildroot} %{dune_add_flags %*} +if [ -d _build/default/_doc/_html ]; then + find _build/default/_doc/_html -name .dune-keep -delete +fi +%ocaml_install_common %{-s} %{-n}} diff --git a/ocaml.spec b/ocaml.spec index 5050261..3b39d37 100644 --- a/ocaml.spec +++ b/ocaml.spec @@ -1,3 +1,6 @@ +# Don't add -Wl,-dT, +%undefine _package_note_flags + # OCaml has a bytecode backend that works on anything with a C # compiler, and a native code backend available on a subset of # architectures. A further subset of architectures support native @@ -15,33 +18,39 @@ %global natdynlink 0 %endif +%global giturl https://github.com/ocaml/ocaml + +# i686 support was dropped in OCaml 5 / Fedora 39. +ExcludeArch: %{ix86} + # These are all the architectures that the tests run on. The tests # take a long time to run, so don't run them on slow machines. -%global test_arches aarch64 %{power64} x86_64 +%global test_arches %{arm64} %{power64} %{riscv64} s390x %{x86_64} # These are the architectures for which the tests must pass otherwise # the build will fail. -%global test_arches_required aarch64 ppc64le x86_64 +#global test_arches_required aarch64 ppc64le x86_64 +%global test_arches_required NONE # Architectures where parallel builds fail. -#%global no_parallel_build_arches aarch64 +#global no_parallel_build_arches aarch64 -# If you want to bootstrap OCaml on a brand new architecture, or if -# you want to build OCaml without requiring an existing OCaml package, -# or if you want to build OCaml exactly as it is built upstream (using -# a binary ocamlc from the previous build), then use ‘--with bootstrap’. -%bcond_with bootstrap +#global rcver +git +%global rcver %{nil} Name: ocaml -Version: 4.07.0 -Release: 4%{?dist} +Version: 5.5.0 +Release: 2%{?dist} Summary: OCaml compiler and programming environment -License: QPL and (LGPLv2+ with exceptions) +License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception -URL: http://www.ocaml.org +URL: https://www.ocaml.org +VCS: git:%{giturl}.git -Source0: http://caml.inria.fr/pub/distrib/ocaml-4.07/ocaml-%{version}.tar.xz +Source0: %{giturl}/archive/%{version}%{rcver}/%{name}-%{version}%{rcver}.tar.gz +Source1: macros.ocaml-rpm +Source2: ocaml_files.py # IMPORTANT NOTE: # @@ -52,68 +61,55 @@ Source0: http://caml.inria.fr/pub/distrib/ocaml-4.07/ocaml-%{version}.tar # # https://pagure.io/fedora-ocaml # -# Current branch: fedora-29-4.07.0 +# Current branch: fedora-45-5.4.1 # # ALTERNATIVELY add a patch to the end of the list (leaving the # existing patches unchanged) adding a comment to note that it should # be incorporated into the git repo at a later time. -# -# Fedora-specific downstream patches. -Patch0001: 0001-Don-t-add-rpaths-to-libraries.patch -Patch0002: 0002-ocamlbyteinfo-ocamlplugininfo-Useful-utilities-from-.patch -Patch0003: 0003-configure-Allow-user-defined-C-compiler-flags.patch - -# Out of tree patch for RISC-V support. -# https://github.com/nojb/riscv-ocaml -Patch0004: 0004-Add-RISC-V-backend.patch -Patch0005: 0005-Copyright-untabify.patch -Patch0006: 0006-fix-caml_c_call-reload-caml_young_limit.patch -Patch0007: 0007-Adapt-to-4.07.patch - -# RISC-V patch to add debuginfo (DWARF) generation. -# Sent upstream 2018-06-05. -Patch0008: 0008-riscv-Emit-debug-info.patch - -%if ! %{with bootstrap} -BuildRequires: ocaml -%endif +# Fedora-specific patches +Patch: 0001-Don-t-add-rpaths-to-libraries.patch +Patch: 0002-configure-Allow-user-defined-C-compiler-flags.patch +BuildRequires: make +BuildRequires: git-core BuildRequires: gcc -BuildRequires: binutils-devel -BuildRequires: ncurses-devel -BuildRequires: gdbm-devel -BuildRequires: emacs +BuildRequires: autoconf BuildRequires: gawk BuildRequires: perl-interpreter -BuildRequires: util-linux -BuildRequires: libICE-devel -BuildRequires: libSM-devel -BuildRequires: libX11-devel -BuildRequires: libXaw-devel -BuildRequires: libXext-devel -BuildRequires: libXft-devel -BuildRequires: libXmu-devel -BuildRequires: libXrender-devel -BuildRequires: libXt-devel -BuildRequires: chrpath +BuildRequires: annobin-annocheck +BuildRequires: pkgconfig(libzstd) +# Documentation requirements +BuildRequires: asciidoc + +# ocamlopt runs gcc to link binaries. Because Fedora includes +# hardening flags automatically, redhat-rpm-config is also required. +# Compressed marshaling requires libzstd-devel. Requires: gcc +Requires: redhat-rpm-config +Requires: libzstd-devel%{?_isa} # Because we pass -c flag to ocaml-find-requires (to avoid circular # dependencies) we also have to explicitly depend on the right version # of ocaml-runtime. -Requires: ocaml-runtime = %{version}-%{release} +Requires: ocaml-runtime%{?_isa} = %{version}-%{release} -# Bundles an MD5 implementation in byterun/md5.{c,h} -Provides: bundled(md5-plumb) +# Force ocaml-srpm-macros to be at the latest version, both for builds +# and installs, since OCaml 5.2 has a different set of native code +# generators than previous versions. +BuildRequires: ocaml-srpm-macros >= 10 +Requires: ocaml-srpm-macros >= 10 Provides: ocaml(compiler) = %{version} -%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' +%if %{native_compiler} +%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' -i Dynlink_cmo_format -i Dynlink_cmxs_format +%else +%global __ocaml_requires_opts -c -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' -i Backend_intf -i Inlining_decision_intf -i Simplify_boxed_integer_ops_intf +%endif %global __ocaml_provides_opts -f '%{buildroot}%{_bindir}/ocamlrun %{buildroot}%{_bindir}/ocamlobjinfo.byte' - %description OCaml is a high-level, strongly-typed, functional and object-oriented programming language from the ML family of languages. @@ -125,10 +121,16 @@ and a comprehensive library. %package runtime +# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole +# LicenseRef-Fedora-Public-Domain: the MD5 implementation in runtime/caml/md5.h +# and runtime/md5.c +License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND LicenseRef-Fedora-Public-Domain Summary: OCaml runtime environment -Requires: util-linux Provides: ocaml(runtime) = %{version} +# Bundles an MD5 implementation in runtime/caml/md5.h and runtime/md5.c +Provides: bundled(md5-plumb) + %description runtime OCaml is a high-level, strongly-typed, functional and object-oriented programming language from the ML family of languages. @@ -139,41 +141,27 @@ bytecode. %package source Summary: Source code for OCaml libraries -Requires: ocaml = %{version}-%{release} +Requires: ocaml%{?_isa} = %{version}-%{release} %description source Source code for OCaml libraries. -%package x11 -Summary: X11 support for OCaml -Requires: ocaml-runtime = %{version}-%{release} -Requires: libX11-devel - -%description x11 -X11 support for OCaml. - - %package ocamldoc +# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole +# LicenseRef-Fedora-Public-Domain: ocamldoc/ocamldoc.sty +License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND LicenseRef-Fedora-Public-Domain Summary: Documentation generator for OCaml -Requires: ocaml = %{version}-%{release} -Provides: ocamldoc +Requires: ocaml%{?_isa} = %{version}-%{release} +Provides: ocamldoc = %{version} %description ocamldoc Documentation generator for OCaml. -%package emacs -Summary: Emacs mode for OCaml -Requires: ocaml = %{version}-%{release} -Requires: emacs(bin) - -%description emacs -Emacs mode for OCaml. - - %package docs Summary: Documentation for OCaml +BuildArch: noarch Requires: ocaml = %{version}-%{release} @@ -186,7 +174,7 @@ This package contains man pages. %package compiler-libs Summary: Compiler libraries for OCaml -Requires: ocaml = %{version}-%{release} +Requires: ocaml%{?_isa} = %{version}-%{release} %description compiler-libs @@ -199,211 +187,253 @@ Note that this exposes internal details of the OCaml compiler which may not be portable between versions. +%package rpm-macros +# LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception: the project as a whole +# BSD-3-Clause: ocaml_files.py +License: LGPL-2.1-or-later WITH OCaml-LGPL-linking-exception AND BSD-3-Clause +Summary: RPM macros for building OCaml packages +BuildArch: noarch +Requires: ocaml = %{version}-%{release} +Requires: python3 + + +%description rpm-macros +This package contains macros that are useful for building OCaml RPMs. + + %prep -%setup -q -T -b 0 -n %{name}-%{version} -%autopatch -p1 -%if ! %{with bootstrap} -cp %{_bindir}/ocamlc.byte boot/ocamlc -cp %{_bindir}/ocamllex.byte boot/ocamllex -%endif +%autosetup -S git -n %{name}-%{version}%{rcver} +# Patches touch configure.ac, so rebuild it: +autoconf --force + %build %ifnarch %{no_parallel_build_arches} -make="make %{?_smp_mflags}" +make="%make_build" %else unset MAKEFLAGS make=make %endif -CFLAGS="$RPM_OPT_FLAGS -fno-strict-aliasing" \ +# Set ocamlmklib default flags to include Fedora linker flags +sed -i '/ld_opts/s|\[\]|["%{build_ldflags}"]|' tools/ocamlmklib.ml + +# Expose a dependency on the math library +sed -i '/^EXTRACAMLFLAGS=/aLINKOPTS=-cclib -lm' otherlibs/unix/Makefile + +# Don't use %%configure macro because it sets --build, --host which +# breaks some incorrect assumptions made by OCaml's configure.ac +# +# See also: +# https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/2O4HBOK6PTQZAFAVIRDVMZGG2PYB2QHM/ +# https://github.com/ocaml/ocaml/issues/8647 +# +# We set --libdir to the unusual directory because we want OCaml to +# install its libraries and other files into a subdirectory. +# +# OC_CFLAGS/OC_LDFLAGS control what flags OCaml passes to the linker +# when doing final linking of OCaml binaries. Setting these is +# necessary to ensure that generated binaries have Fedora hardening +# features. ./configure \ - -bindir %{_bindir} \ - -libdir %{_libdir}/ocaml \ - -x11lib %{_libdir} \ - -x11include %{_includedir} \ - -mandir %{_mandir}/man1 \ - -no-curses + --prefix=%{_prefix} \ + --sysconfdir=%{_sysconfdir} \ + --mandir=%{_mandir} \ + --libdir=%{_libdir}/ocaml \ + --enable-flambda \ +%if %{native_compiler} + --enable-native-compiler \ + --enable-native-toplevel \ +%else + --disable-native-compiler \ + --disable-native-toplevel \ +%endif +%ifarch %{x86_64} %{arm64} +%if 0%{?_include_frame_pointers} + --enable-frame-pointers \ +%endif +%endif +%ifarch %{test_arches} + --enable-ocamltest \ +%else + --disable-ocamltest \ +%endif + OC_CFLAGS='%{build_cflags}' \ + OC_LDFLAGS='%{build_ldflags}' \ + %{nil} $make world %if %{native_compiler} $make opt $make opt.opt %endif -make -C emacs ocamltags -# Currently these tools are supplied by Debian, but are expected -# to go upstream at some point. -includes="-nostdlib -I stdlib -I utils -I parsing -I typing -I bytecomp -I asmcomp -I driver -I otherlibs/unix -I otherlibs/str -I otherlibs/dynlink" -boot/ocamlrun ./ocamlc $includes dynlinkaux.cmo ocamlbyteinfo.ml -o ocamlbyteinfo -# ocamlplugininfo doesn't compile because it needs 'dynheader' (type -# decl) and I have no idea where that comes from -#cp otherlibs/dynlink/natdynlink.ml . -#boot/ocamlrun ./ocamlopt $includes unix.cmxa str.cmxa natdynlink.ml ocamlplugininfo.ml -o ocamlplugininfo +# Build the README and fix up references to other doc files +asciidoc -d book README.adoc +for fil in CONTRIBUTING.md HACKING.adoc INSTALL.adoc README.win32.adoc; do + sed -e "s,\"$fil\",\"https://github.com/ocaml/ocaml/blob/trunk/$fil\"," \ + -i README.html +done %check -%ifarch %{test_arches} -cd testsuite +%ifarch %{ocaml_native_compiler} +# For information only, compile a binary and dump the annocheck data +# from it. Useful so we know if hardening is being enabled, but don't +# fail because not every hardening feature can be enabled here. +echo 'print_endline "hello, world"' > hello.ml +./ocamlopt.opt -verbose -I stdlib hello.ml -o hello ||: +annocheck -v hello ||: +%endif +%ifarch %{test_arches} %ifarch %{test_arches_required} -make -j1 all +make -j1 tests %else -make -j1 all ||: +make -j1 tests ||: %endif %endif %install -make install \ - BINDIR=$RPM_BUILD_ROOT%{_bindir} \ - LIBDIR=$RPM_BUILD_ROOT%{_libdir}/ocaml \ - MANDIR=$RPM_BUILD_ROOT%{_mandir} -perl -pi -e "s|^$RPM_BUILD_ROOT||" $RPM_BUILD_ROOT%{_libdir}/ocaml/ld.conf +%make_install -( - # install emacs files - cd emacs; - make install \ - BINDIR=$RPM_BUILD_ROOT%{_bindir} \ - EMACSDIR=$RPM_BUILD_ROOT%{_datadir}/emacs/site-lisp - make install-ocamltags BINDIR=$RPM_BUILD_ROOT%{_bindir} -) +# OCaml 5.5.0 uses relative paths in ld.conf by default to support relocatable +# OCaml, which we don't need. Overwrite ld.conf with the absolute path. +echo %{_libdir}/ocaml/stublibs > $RPM_BUILD_ROOT%{_libdir}/ocaml/ld.conf echo %{version} > $RPM_BUILD_ROOT%{_libdir}/ocaml/fedora-ocaml-release -# Remove rpaths from stublibs .so files. -chrpath --delete $RPM_BUILD_ROOT%{_libdir}/ocaml/stublibs/*.so +# Remove the installed documentation. We will install it using %%doc +rm -rf $RPM_BUILD_ROOT%{_docdir}/ocaml -install -m 0755 ocamlbyteinfo $RPM_BUILD_ROOT%{_bindir} -#install -m 0755 ocamlplugininfo $RPM_BUILD_ROOT%{_bindir} +mkdir -p $RPM_BUILD_ROOT%{rpmmacrodir} +install -m 0644 %{SOURCE1} $RPM_BUILD_ROOT%{rpmmacrodir}/macros.ocaml-rpm -find $RPM_BUILD_ROOT -name .ignore -delete - -# Remove .cmt and .cmti files, for now. We could package them later. -# See also: http://www.ocamlpro.com/blog/2012/08/20/ocamlpro-and-4.00.0.html -find $RPM_BUILD_ROOT \( -name '*.cmt' -o -name '*.cmti' \) -a -delete +mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat +install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat %files -%doc LICENSE +%license LICENSE %{_bindir}/ocaml -%{_bindir}/ocamlbyteinfo %{_bindir}/ocamlcmt +%{_bindir}/ocamlcp %{_bindir}/ocamldebug -%{_bindir}/ocaml-instr-graph -%{_bindir}/ocaml-instr-report -#%{_bindir}/ocamlplugininfo +%{_bindir}/ocamlmklib +%{_bindir}/ocamlmktop +%{_bindir}/ocamlprof %{_bindir}/ocamlyacc # symlink to either .byte or .opt version %{_bindir}/ocamlc -%{_bindir}/ocamlcp %{_bindir}/ocamldep %{_bindir}/ocamllex -%{_bindir}/ocamlmklib -%{_bindir}/ocamlmktop %{_bindir}/ocamlobjinfo -%{_bindir}/ocamloptp -%{_bindir}/ocamlprof # bytecode versions %{_bindir}/ocamlc.byte -%{_bindir}/ocamlcp.byte %{_bindir}/ocamldep.byte %{_bindir}/ocamllex.byte -%{_bindir}/ocamlmklib.byte -%{_bindir}/ocamlmktop.byte %{_bindir}/ocamlobjinfo.byte -%{_bindir}/ocamloptp.byte -%{_bindir}/ocamlprof.byte %if %{native_compiler} # native code versions %{_bindir}/ocamlc.opt -%{_bindir}/ocamlcp.opt %{_bindir}/ocamldep.opt %{_bindir}/ocamllex.opt -%{_bindir}/ocamlmklib.opt -%{_bindir}/ocamlmktop.opt %{_bindir}/ocamlobjinfo.opt -%{_bindir}/ocamloptp.opt -%{_bindir}/ocamlprof.opt %endif %if %{native_compiler} +%{_bindir}/ocamlnat %{_bindir}/ocamlopt %{_bindir}/ocamlopt.byte %{_bindir}/ocamlopt.opt +%{_bindir}/ocamloptp %endif -#%{_libdir}/ocaml/addlabels -#%{_libdir}/ocaml/scrapelabels -%{_libdir}/ocaml/camlheader -%{_libdir}/ocaml/camlheader_ur %{_libdir}/ocaml/expunge -%{_libdir}/ocaml/extract_crc -%{_libdir}/ocaml/ld.conf %{_libdir}/ocaml/Makefile.config + %{_libdir}/ocaml/*.a -%if %{natdynlink} -%{_libdir}/ocaml/*.cmxs -%endif %if %{native_compiler} %{_libdir}/ocaml/*.cmxa %{_libdir}/ocaml/*.cmx %{_libdir}/ocaml/*.o -%{_libdir}/ocaml/libasmrun_shared.so %endif %{_libdir}/ocaml/*.mli -%{_libdir}/ocaml/libcamlrun_shared.so -%{_libdir}/ocaml/objinfo_helper -%{_libdir}/ocaml/vmthreads/*.mli -%{_libdir}/ocaml/vmthreads/*.a +%{_libdir}/ocaml/sys.ml.in + +%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.mli %if %{native_compiler} -%{_libdir}/ocaml/threads/*.a -%{_libdir}/ocaml/threads/*.cmxa -%{_libdir}/ocaml/threads/*.cmx +%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.a +%{_libdir}/ocaml/{dynlink,runtime_events,str,threads,unix}/*.cmxa +%{_libdir}/ocaml/{dynlink,profiling,runtime_events,str,threads,unix}/*.cmx +%{_libdir}/ocaml/profiling/*.o %endif +%if %{natdynlink} +%{_libdir}/ocaml/{runtime_events,str,unix}/*.cmxs +%endif + +# headers %{_libdir}/ocaml/caml -%exclude %{_libdir}/ocaml/graphicsX11.mli %files runtime -%doc README.adoc LICENSE Changes +%doc README.html Changes +%license LICENSE %{_bindir}/ocamlrun +%{_bindir}/*ocamlrun-a100 %{_bindir}/ocamlrund +%{_bindir}/*ocamlrund-a100 %{_bindir}/ocamlruni +%{_bindir}/*ocamlruni-a100 %dir %{_libdir}/ocaml -%{_libdir}/ocaml/VERSION +%{_libdir}/ocaml/libasmrun*.so +%{_libdir}/ocaml/libcamlrun*.so %{_libdir}/ocaml/*.cmo %{_libdir}/ocaml/*.cmi %{_libdir}/ocaml/*.cma +%{_libdir}/ocaml/ld.conf %{_libdir}/ocaml/stublibs -%{_libdir}/ocaml/target_camlheaderd -%{_libdir}/ocaml/target_camlheaderi -%dir %{_libdir}/ocaml/vmthreads -%{_libdir}/ocaml/vmthreads/*.cmi -%{_libdir}/ocaml/vmthreads/*.cma +%dir %{_libdir}/ocaml/dynlink +%{_libdir}/ocaml/dynlink/META +%{_libdir}/ocaml/dynlink/*.cmi +%{_libdir}/ocaml/dynlink/*.cma +%dir %{_libdir}/ocaml/profiling +%{_libdir}/ocaml/profiling/*.cmo +%{_libdir}/ocaml/profiling/*.cmi +%dir %{_libdir}/ocaml/runtime_events +%{_libdir}/ocaml/runtime_events/META +%{_libdir}/ocaml/runtime_events/*.cmi +%{_libdir}/ocaml/runtime_events/*.cma +%{_libdir}/ocaml/runtime-launch-info +%{_libdir}/ocaml/stdlib +%dir %{_libdir}/ocaml/str +%{_libdir}/ocaml/str/META +%{_libdir}/ocaml/str/*.cmi +%{_libdir}/ocaml/str/*.cma %dir %{_libdir}/ocaml/threads +%{_libdir}/ocaml/threads/META %{_libdir}/ocaml/threads/*.cmi %{_libdir}/ocaml/threads/*.cma +%dir %{_libdir}/ocaml/unix +%{_libdir}/ocaml/unix/META +%{_libdir}/ocaml/unix/*.cmi +%{_libdir}/ocaml/unix/*.cma %{_libdir}/ocaml/fedora-ocaml-release -%exclude %{_libdir}/ocaml/graphicsX11.cmi %files source -%doc LICENSE +%license LICENSE %{_libdir}/ocaml/*.ml - - -%files x11 -%doc LICENSE -%{_libdir}/ocaml/graphicsX11.cmi -%{_libdir}/ocaml/graphicsX11.mli +%{_libdir}/ocaml/*.cmt* +%{_libdir}/ocaml/*/*.cmt* %files ocamldoc -%doc LICENSE +%license LICENSE %doc ocamldoc/Changes.txt %{_bindir}/ocamldoc* %{_libdir}/ocaml/ocamldoc @@ -414,28 +444,249 @@ find $RPM_BUILD_ROOT \( -name '*.cmt' -o -name '*.cmti' \) -a -delete %{_mandir}/man3/* -%files emacs -%doc emacs/README -%{_datadir}/emacs/site-lisp/* -%{_bindir}/ocamltags - - %files compiler-libs -%doc LICENSE -%dir %{_libdir}/ocaml/compiler-libs -%{_libdir}/ocaml/compiler-libs/*.mli -%{_libdir}/ocaml/compiler-libs/*.cmi -%{_libdir}/ocaml/compiler-libs/*.cmo -%{_libdir}/ocaml/compiler-libs/*.cma -%if %{native_compiler} -%{_libdir}/ocaml/compiler-libs/*.a -%{_libdir}/ocaml/compiler-libs/*.cmxa -%{_libdir}/ocaml/compiler-libs/*.cmx -%{_libdir}/ocaml/compiler-libs/*.o -%endif +%license LICENSE +%{_libdir}/ocaml/compiler-libs + + +%files rpm-macros +%{rpmmacrodir}/macros.ocaml-rpm +%{_rpmconfigdir}/redhat/ocaml_files.py %changelog +* Thu Jul 16 2026 Fedora Release Engineering - 5.5.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_45_Mass_Rebuild + +* Tue Jun 23 2026 Jerry James - 5.5.0-1 +- New upstream version 5.5.0 (RHBZ#2442622) +- Drop upstreamed fix for arm64 frame pointers +- Reenable LTO +- Move ld.conf, libasmrun, and libcamlrun to ocaml-runtime +- Drop hardlink dependency; rpm now does this by default +- Drop unused utilx-linux dependency + +* Thu Feb 26 2026 Richard W.M. Jones - 5.4.1-4 +- Backport fix for arm64 frame pointers + +* Fri Feb 20 2026 Richard W.M. Jones - 5.4.1-1 +- New upstream version 5.4.1 (RHBZ#2440356) + +* Fri Jan 16 2026 Fedora Release Engineering - 5.4.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_44_Mass_Rebuild + +* Mon Oct 13 2025 Richard W.M. Jones - 5.4.0-1 +- New upstream version 5.4.0 (RHBZ#2368289) + +* Thu Jul 24 2025 Fedora Release Engineering - 5.3.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_43_Mass_Rebuild + +* Sun Jun 22 2025 Yaakov Selkowitz - 5.3.0-3 +- Fix RPM macros for Python 3.14 + +* Fri Jan 17 2025 Fedora Release Engineering - 5.3.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_42_Mass_Rebuild + +* Thu Jan 9 2025 Jerry James - 5.3.0-1 +- New upstream version 5.3.0 +- Drop upstreamed patches +- BR git-core instead of git + +* Thu Jul 18 2024 Fedora Release Engineering - 5.2.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_41_Mass_Rebuild + +* Wed Jun 19 2024 Richard W.M. Jones - 5.2.0-2 +- Add fix for ppc64le code generation issue found after 5.2.0 was released + +* Thu May 23 2024 Jerry James - 5.2.0-1 +- New upstream version 5.2.0 (RHBZ#2269805) +- Drop upstreamed frame pointer and s390x patches + +* Thu Jan 25 2024 Fedora Release Engineering - 5.1.1-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Sun Jan 21 2024 Fedora Release Engineering - 5.1.1-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild + +* Mon Dec 18 2023 Richard W.M. Jones - 5.1.1-2 +- Add s390x code generation fix + https://github.com/ocaml/ocaml/issues/12829 + +* Mon Dec 11 2023 Richard W.M. Jones - 5.1.1-1 +- New upstream version 5.1.1 (RHBZ#2239227) + +* Tue Nov 14 2023 Yaakov Selkowitz - 5.1.0-5 +- Drop unused BR parallel + +* Fri Oct 06 2023 Richard W.M. Jones - 5.1.0-4 +- Use BR ocaml-srpm-macros to force latest to be built against + +* Thu Oct 05 2023 Richard W.M. Jones - 5.1.0-3 +- Rebuild against updated ocaml-srpm-macros + +* Thu Oct 5 2023 Richard W.M. Jones - 5.1.0-2 +- Add upstream patch added after 5.1.0 + +* Wed Oct 4 2023 Jerry James - 5.1.0-1 +- Version 5.1.0 +- Add LicenseRef-Fedora-Public-Domain to the runtime License field +- New ocaml-rpm-macros subpackage +- Depend on libzstd-devel for compressed marshaling +- Disable LTO + +* Thu Jul 20 2023 Fedora Release Engineering - 5.0.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild + +* Wed Jul 12 2023 Richard W.M. Jones - 5.0.0-3 +- Force ocaml-srpm-macros to be the latest version. + +* Wed Jun 14 2023 Jerry James - 5.0.0-2 +- Version 5.0.0 +- Convert License tag to SPDX +- Ship HTML documentation instead of asciidoc source +- Set ocamlmklib default flags to the Fedora linker flags +- Enable frame pointers on x86_64 + +* Mon Jan 23 2023 Richard W.M. Jones - 4.14.0-5 +- Rebuild OCaml packages for F38 + +* Thu Jan 19 2023 Fedora Release Engineering - 4.14.0-4 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild + +* Mon Sep 5 2022 Richard W.M. Jones - 4.14.0-3 +- Include more upstream patches from 4.14 branch + +* Fri Jul 22 2022 Fedora Release Engineering - 4.14.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild + +* Sat Jun 18 2022 Richard W.M. Jones - 4.14.0-1 +- New upstream version 4.14.0 + +* Thu Jun 9 2022 Jerry James - 4.13.1-4 +- Fix the Source0 URL +- chrpath is no longer needed +- Use the %%license macro +- Build the test binaries so the tests will run + +* Fri Feb 04 2022 Richard W.M. Jones - 4.13.1-4 +- Rebuild 4.13.1 to remove package notes + +* Wed Jan 26 2022 Richard W.M. Jones - 4.13.1-3 +- Disable package note misfeature +- Remove duplicate flags from mkexe + +* Thu Jan 20 2022 Fedora Release Engineering - 4.13.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild + +* Mon Oct 04 2021 Richard W.M. Jones - 4.13.1-1 +- New upstream version 4.13.1 + +* Thu Jul 22 2021 Fedora Release Engineering - 4.12.0-3 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild + +* Wed Jun 23 2021 Richard W.M. Jones - 4.12.0-2 +- Move to final version of upstream patch for non-constant SIGSTKSZ + +* Sun Feb 28 2021 Richard W.M. Jones - 4.12.0-1 +- OCaml 4.12.0 release (RHBZ#1893381). +- Workaround for glibc non-constant SIGSTKSZ + (https://github.com/ocaml/ocaml/issues/10250) +- Package *.cmt and *.cmti files. +- Remove objinfo_helper since it is no longer built. + +* Tue Jan 26 2021 Fedora Release Engineering - 4.11.1-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild + +* Tue Sep 01 2020 Richard W.M. Jones - 4.11.1-1 +- OCaml 4.11.1 release (RHBZ#1870368#c26). + +* Fri Aug 21 2020 Richard W.M. Jones - 4.11.0-1 +- OCaml 4.11.0 release (RHBZ#1870368). + +* Tue Aug 04 2020 Richard W.M. Jones - 4.11.0-0.9.dev2 +- Bump and rebuild to fix DWARF versioning issues. +- Enable LTO again. + +* Tue Jul 28 2020 Fedora Release Engineering - 4.11.0-0.7.dev2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild + +* Tue Jul 14 2020 Tom Stellard - 4.11.0-0.6.dev2 +- Use make macros +- https://fedoraproject.org/wiki/Changes/UseMakeBuildInstallMacro + +* Wed Jul 01 2020 Jeff Law - 4.11.0-0.5.dev2.fc33 +- Disable LTO + +* Mon May 04 2020 Richard W.M. Jones - 4.11.0-0.4.dev2.fc33 +- Move to OCaml 4.11.0+dev2-2020-04-22. +- Backport upstream RISC-V backend from 4.12 + fixes. +- Enable tests on riscv64. +- Disable ocaml-instr-* tools on riscv64. + +* Tue Apr 21 2020 Richard W.M. Jones - 4.11.0-0.3.pre.fc33 +- Add fixes for various issues found in the previous build. + +* Fri Apr 17 2020 Richard W.M. Jones - 4.11.0-0.2.pre.fc33 +- Move to OCaml 4.11.0 pre-release with support for RISC-V. + +* Sat Apr 11 2020 Richard W.M. Jones - 4.10.0-4.fc33 +- Fix RISC-V backend. + +* Thu Apr 02 2020 Richard W.M. Jones - 4.10.0-3.fc33 +- Update all OCaml dependencies for RPM 4.16. + +* Thu Feb 27 2020 Richard W.M. Jones - 4.10.0-2.fc33 +- Add dist tag. + +* Tue Feb 25 2020 Richard W.M. Jones - 4.10.0-1 +- OCaml 4.10.0 final. + +* Wed Jan 29 2020 Fedora Release Engineering - 4.10.0-0.beta1.0.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild + +* Sat Jan 18 2020 Richard W.M. Jones - 4.10.0-0.beta1 +- OCaml 4.10.0+beta1. + +* Tue Jan 07 2020 Richard W.M. Jones - 4.09.0-13 +- Bump release and rebuild. + +* Tue Jan 07 2020 Richard W.M. Jones - 4.09.0-4 +- OCaml 4.09.0 for riscv64 + +* Tue Dec 10 2019 Richard W.M. Jones - 4.09.0-3 +- Require redhat-rpm-config to get hardening flags when linking. + +* Thu Dec 05 2019 Richard W.M. Jones - 4.09.0-2 +- OCaml 4.09.0 final. +- Use autosetup, remove old setup line. +- Remove ocamloptp binaries. +- Rename target_camlheader[di] -> camlheader[di] files. +- Remove vmthreads - old threading library which is no longer built. +- Remove x11 subpackage which is obsolete. +- Further fixes to CFLAGS and annobin. + +* Fri Aug 16 2019 Richard W.M. Jones - 4.08.1-1 +- OCaml 4.08.1 final. + +* Tue Jul 30 2019 Richard W.M. Jones - 4.08.1-0.rc2.1 +- OCaml 4.08.1+rc2. +- Include fix for miscompilation of off_t on 32 bit architectures. + +* Thu Jul 25 2019 Fedora Release Engineering - 4.08.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild + +* Thu Jun 27 2019 Richard W.M. Jones - 4.08.0-1 +- OCaml 4.08.0 (RHBZ#1673688). + +* Fri Apr 26 2019 Richard W.M. Jones - 4.08.0-0.beta3.1 +- OCaml 4.08.0 beta 3 (RHBZ#1673688). +- emacs subpackage has been dropped (from upstream): + https://github.com/ocaml/ocaml/pull/2078#issuecomment-443322613 + https://github.com/Chris00/caml-mode +- Remove ocamlbyteinfo and ocamlpluginfo, neither can be compiled. +- Disable tests on all architectures, temporarily hopefully. +- Package threads/*.mli files. + * Fri Feb 01 2019 Fedora Release Engineering - 4.07.0-4 - Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild diff --git a/ocaml_files.py b/ocaml_files.py new file mode 100644 index 0000000..0e4658e --- /dev/null +++ b/ocaml_files.py @@ -0,0 +1,451 @@ +# Copyright 2022-3, Jerry James +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the +# distribution. +# 3. Neither the name of Red Hat nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import argparse +import os +import shutil +import string +import sys +from collections.abc import Iterable, Iterator +from enum import Enum, auto +from typing import Callable, final + +# Version of this script +version=2 + +# +# BUILDROOT CATEGORIZATION +# + +# Directories to ignore when generating %dir entries +root_dirs: set[str] = { + '/', + '/etc', + '/usr', + '/usr/bin', + '/usr/lib', + '/usr/lib/ocaml', + '/usr/lib/ocaml/caml', + '/usr/lib/ocaml/stublibs', + '/usr/lib/ocaml/threads', + '/usr/lib64', + '/usr/lib64/ocaml', + '/usr/lib64/ocaml/caml', + '/usr/lib64/ocaml/stublibs', + '/usr/lib64/ocaml/threads', + '/usr/libexec', + '/usr/sbin', + '/usr/share', + '/usr/share/doc' +} + +def find_buildroot_toplevel(buildroot: str) -> list[str]: + """Find toplevel files and directories in the buildroot. + + :param str buildroot: path to the buildroot + :return: a list of toplevel files and directories in the buildroot + """ + bfiles: list[str] = [] + for path, dirs, files in os.walk(buildroot): + for i in range(len(dirs) - 1, -1, -1): + d = os.path.join(path, dirs[i])[len(buildroot):] + if d not in root_dirs and not d.startswith('/usr/share/man'): + bfiles.append(d) + del dirs[i] + for f in files: + realfile = os.path.join(path, f)[len(buildroot):] + if realfile.startswith('/usr/share/man'): + bfiles.append(realfile + '*') + else: + bfiles.append(realfile) + return bfiles + +# File suffixes that go into a devel subpackage +dev_suffixes: set[str] = { + 'a', 'cmo', 'cmt', 'cmti', 'cmx', 'cmxa', 'h', 'idl', 'ml', 'mli', 'o' +} + +def is_devel_file(filname: str) -> bool: + """Determine whether a file belongs to a devel subpackage. + + :param str filname: the filename to check + :return: True if the file belongs to a devel subpackage, else False + """ + return (filname == 'dune-package' or filname == 'opam' or + (os.path.splitext(filname)[1][1:] in dev_suffixes + and not filname.endswith('_top_init.ml'))) + +def find_buildroot_all(buildroot: str, devel: bool, add_star: bool) -> list[set[str]]: + """Find all files and directories in the buildroot and optionally + categorize them as 'main' or 'devel'. + + :param Namespace args: parsed command line arguments + :param bool devel: True to split into 'main' and 'devel', False otherwise + :param bool add_star: True to add a star to man page filenames + :return: a list of files and directories, in this order: main files, + main directories, devel files, and devel directories + """ + bfiles: list[set[str]] = [set(), set(), set()] + bdirs: set[str] = set() + for path, dirs, files in os.walk(buildroot): + for d in dirs: + realdir = os.path.join(path, d)[len(buildroot):] + if realdir not in root_dirs and not realdir.startswith('/usr/share/man'): + bdirs.add(realdir) + for f in files: + realfile = os.path.join(path, f)[len(buildroot):] + if devel and is_devel_file(os.path.basename(realfile)): + bfiles[2].add(realfile) + else: + if add_star and realfile.startswith('/usr/share/man'): + bfiles[0].add(realfile + '*') + else: + bfiles[0].add(realfile) + parentdir = os.path.dirname(realfile) + if parentdir in bdirs: + bfiles[1].add(parentdir) + bdirs.remove(parentdir) + # Catch intermediate directories, as in ocaml-mtime + parentdir = os.path.dirname(parentdir) + if parentdir in bdirs: + bfiles[1].add(parentdir) + bdirs.remove(parentdir) + bfiles.append(bdirs) + return bfiles + +# +# INSTALL FILE LEXER AND PARSER +# + +class TokenType(Enum): + """The types of tokens that can appear in an opam *.install file.""" + ERROR = auto() + COLON = auto() + LBRACE = auto() + RBRACE = auto() + LBRACK = auto() + RBRACK = auto() + STRING = auto() + FIELD = auto() + +@final +class InstallFileLexer(Iterator[tuple[TokenType, str]]): + """Convert an opam *.install file into a sequence of tokens.""" + __slots__ = ['index', 'text'] + + def __init__(self, filname: str) -> None: + """Create an opam *.install file lexer. + + :param str filname: the name of the file to read from + """ + self.index = 0 + with open(filname, 'r') as f: + # Limit reads to 4 MB in case this file is bogus. + # Most install files are under 4K. + self.text = f.read(4194304) + + def skip_whitespace(self) -> None: + """Skip over whitespace in the input.""" + while self.index < len(self.text) and \ + (self.text[self.index] == '#' or + self.text[self.index] in string.whitespace): + if self.text[self.index] == '#': + while (self.index < len(self.text) and + self.text[self.index] != '\n' and + self.text[self.index] != '\r'): + self.index += 1 + else: + self.index += 1 + + def __next__(self) -> tuple[TokenType, str]: + """Get the next token from the opam *.install file. + + :return: a pair containing the type and text of the next token + """ + self.skip_whitespace() + if self.index < len(self.text): + ch = self.text[self.index] + if ch == ':': + self.index += 1 + return (TokenType.COLON, ch) + if ch == '{': + self.index += 1 + return (TokenType.LBRACE, ch) + if ch == '}': + self.index += 1 + return (TokenType.RBRACE, ch) + if ch == '[': + self.index += 1 + return (TokenType.LBRACK, ch) + if ch == ']': + self.index += 1 + return (TokenType.RBRACK, ch) + if ch == '"': + start = self.index + 1 + end = start + while end < len(self.text) and self.text[end] != '"': + end += 2 if self.text[end] == '\\' else 1 + self.index = end + 1 + return (TokenType.STRING, self.text[start:end]) + if ch in string.ascii_letters: + start = self.index + end = start + 1 + while (end < len(self.text) and + (self.text[end] == '_' or + self.text[end] in string.ascii_letters)): + end += 1 + self.index = end + return (TokenType.FIELD, self.text[start:end]) + return (TokenType.ERROR, ch) + else: + raise StopIteration + +@final +class InstallFileParser(Iterable[tuple[str, bool, str, str]]): + """Parse opam *.install files.""" + + __slots__ = ['pkgname', 'lexer', 'libdir'] + + def __init__(self, filname: str, libdir: str) -> None: + """Initialize an OCaml .install file parser. + + :param str filname: name of the .install file to parse + :param str libdir: the OCaml library directory + """ + self.pkgname = os.path.splitext(os.path.basename(filname))[0] + self.lexer = InstallFileLexer(filname) + self.libdir = libdir + + def __iter__(self) -> Iterator[tuple[str, bool, str, str]]: + """Parse a .install file. + If there are any parse errors, we assume this file is not really an + opam .install file and abandon the parse. + """ + # Map opam installer names to directories + opammap: dict[str, str] = { + 'lib': os.path.join(self.libdir, self.pkgname), + 'lib_root': self.libdir, + 'libexec': os.path.join(self.libdir, self.pkgname), + 'libexec_root': self.libdir, + 'bin': '/usr/bin', + 'sbin': '/usr/sbin', + 'toplevel': os.path.join(self.libdir, 'toplevel'), + 'share': os.path.join('/usr/share', self.pkgname), + 'share_root': '/usr/share', + 'etc': os.path.join('/etc', self.pkgname), + 'doc': os.path.join('/usr/doc', self.pkgname), + 'stublibs': os.path.join(self.libdir, 'stublibs'), + 'man': '/usr/share/man' + } + + # Parse the file + try: + toktyp, token = next(self.lexer) + while toktyp == TokenType.FIELD: + libname = token + toktyp, token = next(self.lexer) + if toktyp != TokenType.COLON: + return + + toktyp, token = next(self.lexer) + if toktyp != TokenType.LBRACK: + return + + directory = opammap.get(libname) + if not directory: + return + + toktyp, token = next(self.lexer) + while toktyp == TokenType.STRING: + source = token + optional = source[0] == '?' + if optional: + source = source[1:] + nexttp, nexttk = next(self.lexer) + if nexttp == TokenType.LBRACE: + nexttp, nexttk = next(self.lexer) + if nexttp == TokenType.STRING: + filname = os.path.join(directory, nexttk) + bracetp, bractk = next(self.lexer) + if bracetp != TokenType.RBRACE: + return + nexttp, nexttk = next(self.lexer) + else: + return + elif libname == 'man': + index = token.rfind('.') + if index < 0: + return + mandir = os.path.join(directory, 'man' + token[index+1:]) + filname = os.path.join(mandir, os.path.basename(token)) + else: + filname = os.path.join(directory, os.path.basename(token)) + toktyp, token = nexttp, nexttk + yield (self.pkgname, optional, source, filname) + + if toktyp != TokenType.RBRACK: + return + toktyp, token = next(self.lexer) + except StopIteration: + return + +def install_files(buildroot: str, libdir: str) -> None: + """Install the files listed in opam .install files in the buildroot. + + For some projects, there are install files in both the project root + directory and somewhere under "_build", so be careful not to parse the same + install file twice. + + :param str buildroot: path to the buildroot + :param str libdir: the OCaml library directory + """ + install_files = set() + for path, dirs, files in os.walk('.'): + for f in files: + if f.endswith('.install') and f not in install_files: + install_files.add(f) + parser = InstallFileParser(os.path.join(path, f), libdir) + for _, optional, source, filname in parser: + if not optional or os.path.exists(source): + installpath = os.path.join(buildroot, filname[1:]) + os.makedirs(os.path.dirname(installpath), exist_ok=True) + shutil.copy2(source, installpath) + +def get_package_map(buildroot: str, libdir: str, devel: bool) -> dict[str, set[str]]: + """Create a map from package names to installed files from the opam .install + files in the buildroot. + + For some projects, there are install files in both the project root + directory and somewhere under "_build", so be careful not to parse the same + install file twice.""" + + pmap: dict[str, set[str]] = dict() + install_files = set() + + def add_pkg(pkgname: str, filname: str) -> None: + """Add a mapping from a package name to a filename. + + :param str pkgname: the package that acts as the map key + :param str filname: the filename to add to the package set + """ + if pkgname not in pmap: + pmap[pkgname] = set() + pmap[pkgname].add(filname) + + installed = find_buildroot_all(buildroot, devel, False) + for path, dirs, files in os.walk('.'): + for f in files: + if f.endswith('.install') and f not in install_files: + install_files.add(f) + parser = InstallFileParser(os.path.join(path, f), libdir) + for pkgname, _, _, filname in parser: + if filname in installed[0]: + if filname.startswith('/usr/share/man'): + add_pkg(pkgname, filname + '*') + else: + add_pkg(pkgname, filname) + dirname = os.path.dirname(filname) + if dirname in installed[1]: + add_pkg(pkgname, '%dir ' + dirname) + installed[1].remove(dirname) + elif filname in installed[2]: + if filname.startswith('/usr/share/man'): + add_pkg(pkgname + '-devel', filname + '*') + else: + add_pkg(pkgname + '-devel', filname) + dirname = os.path.dirname(filname) + if dirname in installed[3]: + add_pkg(pkgname + '-devel', '%dir ' + dirname) + installed[3].remove(dirname) + return pmap + +# +# MAIN INTERFACE +# + +def ocaml_files(no_devel: bool, separate: bool, install: bool, buildroot: str, + libdir: str) -> None: + """Generate %files lists from an installed buildroot. + + :param bool no_devel: False to split files into a main package and a devel + package + :param bool separate: True to place each OCaml module in an RPM package + :param bool install: True to install files, False to generate %files + :param str buildroot: the installed buildroot + :param str libdir: the OCaml library directory + """ + if install: + install_files(buildroot, libdir) + elif separate: + pkgmap = get_package_map(buildroot, libdir, not no_devel) + for pkg in pkgmap: + with open('.ofiles-' + pkg, 'w') as f: + for entry in pkgmap[pkg]: + f.write(entry + '\n') + elif no_devel: + with open('.ofiles', 'w') as f: + for entry in find_buildroot_toplevel(buildroot): + f.write(entry + '\n') + else: + files = find_buildroot_all(buildroot, True, True) + with open('.ofiles', 'w') as f: + for entry in files[0]: + f.write(entry + '\n') + for entry in files[1]: + f.write('%dir ' + entry + '\n') + with open('.ofiles-devel', 'w') as f: + for entry in files[2]: + f.write(entry + '\n') + for entry in files[3]: + f.write('%dir ' + entry + '\n') + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description='Support for building OCaml RPM packages') + parser.add_argument('-i', '--install', + action='store_true', + default=False, + help='install files instead of generating %%files') + parser.add_argument('-n', '--no-devel', + action='store_true', + default=False, + help='suppress creation of a devel subpackage') + parser.add_argument('-s', '--separate', + action='store_true', + default=False, + help='separate packaging. Each OCaml module is in a distinct RPM package. All modules are in a single RPM package by default.') + parser.add_argument('-v', '--version', + action='version', + version=f'%(prog)s {str(version)}') + parser.add_argument('buildroot', help='RPM build root') + parser.add_argument('libdir', help='OCaml library directory') + args = parser.parse_args() + ocaml_files(args.no_devel, + args.separate, + args.install, + args.buildroot, + args.libdir) diff --git a/sources b/sources index c116389..7c0afd0 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ocaml-4.07.0.tar.xz) = 1c27c2c81919af6b51824fb69f203ebca009ab093af0dffb0dbe66d08ba980525ee14e9426edf142c527315144602ac9ef6e36d2266714b5f7ccc7c063e75ac8 +SHA512 (ocaml-5.5.0.tar.gz) = bf13c18cd1fc7b2e5e9623024ea8623710f646ff2fbc0f59dab70e4d4318ed8623bdcc3ec59ce37af07af2b767f520dea23fb474c26297b3e858b6c8e080b4e6 diff --git a/tests/basic-test.sh b/tests/basic-test.sh new file mode 100755 index 0000000..514bea0 --- /dev/null +++ b/tests/basic-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash - +set -e +set -x + +# Compile a trivial program and run it. +echo 'print_endline "hello, world"' > hello.ml +ocamlc.opt hello.ml -o hello +./hello +ocamlopt.opt hello.ml -o hello +./hello diff --git a/tests/tests.yml b/tests/tests.yml new file mode 100755 index 0000000..b9ec89a --- /dev/null +++ b/tests/tests.yml @@ -0,0 +1,11 @@ +- hosts: localhost + roles: + - role: standard-test-basic + tags: + - classic + required_packages: + - ocaml + tests: + - simple: + dir: . + run: ./basic-test.sh