diff --git a/.gitignore b/.gitignore index 0244410..33b0bdd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /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 9c8df31..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 4c7732daae8f0d2a622f91f5ff3add5c2248a2e3 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/5] 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 dbad0b74f..c920a5337 100644 ---- a/tools/Makefile -+++ b/tools/Makefile -@@ -154,8 +154,8 @@ $(call byte_and_opt,ocamlmklib,ocamlmklibconfig.cmo config.cmo \ - ocamlmklibconfig.ml: $(ROOTDIR)/Makefile.config 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)"';) \ - > 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.28.0.rc2 +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 index 8516bb4..74de99b 100644 --- a/0002-configure-Allow-user-defined-C-compiler-flags.patch +++ b/0002-configure-Allow-user-defined-C-compiler-flags.patch @@ -1,27 +1,25 @@ -From 441ad77a0c89f4abdf104c668d579607f338a052 Mon Sep 17 00:00:00 2001 +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/5] configure: Allow user defined C compiler flags. +Subject: [PATCH 2/2] configure: Allow user defined C compiler flags. --- - configure.ac | 4 ++++ - 1 file changed, 4 insertions(+) + configure.ac | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac -index aa5f26f28..5153853b7 100644 +index fb60c7c14c..f6a493ccf5 100644 --- a/configure.ac +++ b/configure.ac -@@ -609,6 +609,10 @@ AS_CASE([$host], - internal_cflags="$gcc_warnings"], - [common_cflags="-O"])]) - -+# Allow CFLAGS and LDFLAGS to be added. -+common_cflags="$common_cflags $CFLAGS" -+cclibs="$cclibs $LDFLAGS" -+ - internal_cppflags="-DCAML_NAME_SPACE $internal_cppflags" - - # Enable SSE2 on x86 mingw to avoid using 80-bit registers. +@@ -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.28.0.rc2 +2.52.0 diff --git a/0003-configure-Remove-incorrect-assumption-about-cross-co.patch b/0003-configure-Remove-incorrect-assumption-about-cross-co.patch deleted file mode 100644 index 1423b0d..0000000 --- a/0003-configure-Remove-incorrect-assumption-about-cross-co.patch +++ /dev/null @@ -1,43 +0,0 @@ -From 3318c5b805d8d6ae1d571f18f682c9f701b712e2 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Fri, 26 Apr 2019 16:16:29 +0100 -Subject: [PATCH 3/5] configure: Remove incorrect assumption about - cross-compiling. - -See https://github.com/ocaml/ocaml/issues/8647#issuecomment-487094390 ---- - configure.ac | 11 ++++++----- - 1 file changed, 6 insertions(+), 5 deletions(-) - -diff --git a/configure.ac b/configure.ac -index 5153853b7..4e97474a2 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -511,10 +511,11 @@ AS_IF( - - # Are we building a cross-compiler - --AS_IF( -- [test x"$host" = x"$target"], -- [cross_compiler=false], -- [cross_compiler=true]) -+#AS_IF( -+# [test x"$host" = x"$target"], -+# [cross_compiler=false], -+# [cross_compiler=true]) -+cross_compiler=false - - # Checks for programs - -@@ -1021,7 +1022,7 @@ AS_CASE([$arch], - - # Assembler - --AS_IF([test -n "$host_alias"], [toolpref="${host_alias}-"], [toolpref=""]) -+#AS_IF([test -n "$host_alias"], [toolpref="${host_alias}-"], [toolpref=""]) - - # We first compute default values for as and aspp - # If values have been given by the user then they take precedence over --- -2.28.0.rc2 - diff --git a/0004-Remove-configure-from-.gitattributes.patch b/0004-Remove-configure-from-.gitattributes.patch deleted file mode 100644 index b9003f7..0000000 --- a/0004-Remove-configure-from-.gitattributes.patch +++ /dev/null @@ -1,28 +0,0 @@ -From 01d8e3f82adb382fb90af15879f722e824834c84 Mon Sep 17 00:00:00 2001 -From: "Richard W.M. Jones" -Date: Sat, 18 Jan 2020 11:31:27 +0000 -Subject: [PATCH 4/5] Remove configure from .gitattributes. - -It's not a binary file. ---- - .gitattributes | 4 ---- - 1 file changed, 4 deletions(-) - -diff --git a/.gitattributes b/.gitattributes -index 200eb49c6..d871764de 100644 ---- a/.gitattributes -+++ b/.gitattributes -@@ -29,10 +29,6 @@ - - /boot/menhir/parser.ml* -diff - --# configure is declared as binary so that it doesn't get included in diffs. --# This also means it will have the correct Unix line-endings, even on Windows. --/configure binary -- - # 'union' merge driver just unions textual content in case of conflict - # http://krlmlr.github.io/using-gitattributes-to-avoid-merge-conflicts/ - /.mailmap merge=union --- -2.28.0.rc2 - diff --git a/0005-Fix-type-mismatches-between-definition-and-declarati.patch b/0005-Fix-type-mismatches-between-definition-and-declarati.patch deleted file mode 100644 index 587f5a6..0000000 --- a/0005-Fix-type-mismatches-between-definition-and-declarati.patch +++ /dev/null @@ -1,69 +0,0 @@ -From 122db7141d292d63cfbe2c7d7a4280cc73194ece Mon Sep 17 00:00:00 2001 -From: Xavier Leroy -Date: Wed, 5 Aug 2020 11:17:52 +0200 -Subject: [PATCH 5/5] Fix type mismatches between definition and declaration - (#9830) - -The C global variable caml_fl_merge and the C function -caml_spacetime_my_profinfo (bytecode version) were declared and -defined with different types. This is undefined behavior and -can cause link-time errors with link-time optimization (LTO). - -Closes: #9825 ---- - runtime/major_gc.c | 4 ++-- - runtime/spacetime_byt.c | 7 ++++++- - 2 files changed, 8 insertions(+), 3 deletions(-) - -diff --git a/runtime/major_gc.c b/runtime/major_gc.c -index 5e4f06bce..c8f5a3281 100644 ---- a/runtime/major_gc.c -+++ b/runtime/major_gc.c -@@ -63,7 +63,7 @@ uintnat caml_dependent_size, caml_dependent_allocated; - double caml_extra_heap_resources; - uintnat caml_fl_wsz_at_phase_change = 0; - --extern char *caml_fl_merge; /* Defined in freelist.c. */ -+extern value caml_fl_merge; /* Defined in freelist.c. */ - - static char *markhp, *chunk, *limit; - static double p_backlog = 0.0; /* backlog for the gc speedup parameter */ -@@ -570,7 +570,7 @@ static void sweep_slice (intnat work) - break; - case Caml_blue: - /* Only the blocks of the free-list are blue. See [freelist.c]. */ -- caml_fl_merge = Bp_hp (hp); -+ caml_fl_merge = (value) Bp_hp (hp); - break; - default: /* gray or black */ - CAMLassert (Color_hd (hd) == Caml_black); -diff --git a/runtime/spacetime_byt.c b/runtime/spacetime_byt.c -index 2b0bf1dc2..b75fb0980 100644 ---- a/runtime/spacetime_byt.c -+++ b/runtime/spacetime_byt.c -@@ -12,8 +12,12 @@ - /* */ - /**************************************************************************/ - -+#define CAML_INTERNALS -+ - #include "caml/fail.h" - #include "caml/mlvalues.h" -+#include "caml/io.h" -+#include "caml/spacetime.h" - - int caml_ensure_spacetime_dot_o_is_included = 42; - -@@ -22,7 +26,8 @@ CAMLprim value caml_spacetime_only_works_for_native_code(value foo, ...) - caml_failwith("Spacetime profiling only works for native code"); - } - --uintnat caml_spacetime_my_profinfo (void) -+uintnat caml_spacetime_my_profinfo (spacetime_unwind_info_cache * cached, -+ uintnat wosize) - { - return 0; - } --- -2.28.0.rc2 - 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 944a6c2..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,9 +18,14 @@ %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} riscv64 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 @@ -30,17 +38,19 @@ %global rcver %{nil} Name: ocaml -Version: 4.11.1 -Release: 1%{?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: https://caml.inria.fr/pub/distrib/ocaml-4.11/ocaml-%{version}.tar.xz -#Source0: https://github.com/ocaml/ocaml/archive/%%{version}.tar.gz +Source0: %{giturl}/archive/%{version}%{rcver}/%{name}-%{version}%{rcver}.tar.gz +Source1: macros.ocaml-rpm +Source2: ocaml_files.py # IMPORTANT NOTE: # @@ -51,51 +61,55 @@ Source0: https://caml.inria.fr/pub/distrib/ocaml-4.11/ocaml-%{version}.ta # # https://pagure.io/fedora-ocaml # -# Current branch: fedora-34-4.11.1 +# 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. -Patch0001: 0001-Don-t-add-rpaths-to-libraries.patch -Patch0002: 0002-configure-Allow-user-defined-C-compiler-flags.patch -Patch0003: 0003-configure-Remove-incorrect-assumption-about-cross-co.patch -Patch0004: 0004-Remove-configure-from-.gitattributes.patch +# Fedora-specific patches +Patch: 0001-Don-t-add-rpaths-to-libraries.patch +Patch: 0002-configure-Allow-user-defined-C-compiler-flags.patch -# Fix compilation with LTO (upstream, but not in 4.11 branch). -Patch0005: 0005-Fix-type-mismatches-between-definition-and-declarati.patch - -BuildRequires: git +BuildRequires: make +BuildRequires: git-core BuildRequires: gcc BuildRequires: autoconf -BuildRequires: binutils-devel -BuildRequires: ncurses-devel -BuildRequires: gdbm-devel BuildRequires: gawk BuildRequires: perl-interpreter -BuildRequires: util-linux -BuildRequires: /usr/bin/annocheck -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. @@ -107,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. @@ -121,16 +141,19 @@ 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 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. @@ -138,6 +161,7 @@ Documentation generator for OCaml. %package docs Summary: Documentation for OCaml +BuildArch: noarch Requires: ocaml = %{version}-%{release} @@ -150,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 @@ -163,6 +187,20 @@ 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 %autosetup -S git -n %{name}-%{version}%{rcver} # Patches touch configure.ac, so rebuild it: @@ -177,28 +215,65 @@ unset MAKEFLAGS make=make %endif +# 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. # -# Force --host because of: -# https://lists.fedoraproject.org/archives/list/devel@lists.fedoraproject.org/thread/2O4HBOK6PTQZAFAVIRDVMZGG2PYB2QHM/ -# (see also https://github.com/ocaml/ocaml/issues/8647) -# # 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 \ - OC_CFLAGS="$CFLAGS" \ - OC_LDFLAGS="$LDFLAGS" \ +./configure \ + --prefix=%{_prefix} \ + --sysconfdir=%{_sysconfdir} \ + --mandir=%{_mandir} \ --libdir=%{_libdir}/ocaml \ - --host=`./build-aux/config.guess` + --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 +# 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 %{ocaml_native_compiler} @@ -211,143 +286,154 @@ annocheck -v hello ||: %endif %ifarch %{test_arches} -cd testsuite - %ifarch %{test_arches_required} -make -j1 all +make -j1 tests %else -make -j1 all ||: +make -j1 tests ||: %endif %endif %install %make_install -perl -pi -e "s|^$RPM_BUILD_ROOT||" $RPM_BUILD_ROOT%{_libdir}/ocaml/ld.conf + +# 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 -find $RPM_BUILD_ROOT -name .ignore -delete +mkdir -p $RPM_BUILD_ROOT%{rpmmacrodir} +install -m 0644 %{SOURCE1} $RPM_BUILD_ROOT%{rpmmacrodir}/macros.ocaml-rpm -# 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 - -# Remove this file. It's only created in certain situations and it's -# unclear why it is created at all. -rm -f $RPM_BUILD_ROOT%{_libdir}/ocaml/eventlog_metadata +mkdir -p $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat +install -m 0644 %{SOURCE2} $RPM_BUILD_ROOT%{_rpmconfigdir}/redhat %files -%doc LICENSE +%license LICENSE %{_bindir}/ocaml %{_bindir}/ocamlcmt +%{_bindir}/ocamlcp %{_bindir}/ocamldebug -#{_bindir}/ocaml-instr-graph -#{_bindir}/ocaml-instr-report +%{_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/threads/*.mli +%{_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 %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/camlheaderd -%{_libdir}/ocaml/camlheaderi +%{_libdir}/ocaml/ld.conf %{_libdir}/ocaml/stublibs +%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 %files source -%doc LICENSE +%license LICENSE %{_libdir}/ocaml/*.ml +%{_libdir}/ocaml/*.cmt* +%{_libdir}/ocaml/*/*.cmt* %files ocamldoc -%doc LICENSE +%license LICENSE %doc ocamldoc/Changes.txt %{_bindir}/ocamldoc* %{_libdir}/ocaml/ocamldoc @@ -359,21 +445,158 @@ rm -f $RPM_BUILD_ROOT%{_libdir}/ocaml/eventlog_metadata %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). 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 1e5a596..7c0afd0 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (ocaml-4.11.1.tar.xz) = ca34655dc22257aa48aeb48a9cf56bde177aa0f0e7f3965f334939934801a206ed5667b7ab0cc291df9e6bf1bb3251f7384f078ea5562e647fde93167ecb1e84 +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