summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fileattrs/ocaml.attr7
-rw-r--r--scripts/Makefile.am4
-rw-r--r--scripts/ocaml-find-provides.sh56
-rw-r--r--scripts/ocaml-find-requires.sh68
-rw-r--r--scripts/ocamldeps.sh243
5 files changed, 249 insertions, 129 deletions
diff --git a/fileattrs/ocaml.attr b/fileattrs/ocaml.attr
index 5fd087077..ad698b5fa 100644
--- a/fileattrs/ocaml.attr
+++ b/fileattrs/ocaml.attr
@@ -1,3 +1,4 @@
-%__ocaml_provides %{_rpmconfigdir}/ocaml-find-provides.sh
-%__ocaml_requires %{_rpmconfigdir}/ocaml-find-requires.sh
-%__ocaml_magic ^(Objective caml|OCaml) .*$
+%__ocaml_provides %{_rpmconfigdir}/ocamldeps.sh --provides
+%__ocaml_requires %{_rpmconfigdir}/ocamldeps.sh --requires
+%__ocaml_magic ^(ELF|Objective caml|OCaml) .*$
+%__ocaml_path .(cma|cmi|cmo|cmx|cmxa|cmxs)$
diff --git a/scripts/Makefile.am b/scripts/Makefile.am
index 791b49bee..2b8367d95 100644
--- a/scripts/Makefile.am
+++ b/scripts/Makefile.am
@@ -19,7 +19,7 @@ EXTRA_DIST = \
tgpg vpkg-provides.sh \
find-requires find-provides \
find-requires.php find-provides.php \
- ocaml-find-requires.sh ocaml-find-provides.sh \
+ ocamldeps.sh \
pkgconfigdeps.sh libtooldeps.sh metainfo.prov \
fontconfig.prov desktop-file.prov script.req
@@ -34,7 +34,7 @@ rpmconfig_SCRIPTS = \
perl.prov perl.req pythondeps.sh pythondistdeps.py \
metainfo.prov \
pkgconfigdeps.sh libtooldeps.sh \
- ocaml-find-requires.sh ocaml-find-provides.sh \
+ ocamldeps.sh \
fontconfig.prov desktop-file.prov script.req \
rpmdb_dump rpmdb_load \
rpm2cpio.sh tgpg
diff --git a/scripts/ocaml-find-provides.sh b/scripts/ocaml-find-provides.sh
deleted file mode 100644
index 985709e87..000000000
--- a/scripts/ocaml-find-provides.sh
+++ /dev/null
@@ -1,56 +0,0 @@
-#!/bin/sh -
-# OCaml-specific "find-provides" for RPM.
-# By Richard W.M. Jones <rjones@redhat.com>
-# $Id: ocaml-find-provides.sh,v 1.2 2007/09/06 11:49:59 rjones Exp $
-
-#set -x
-
-# Usage:
-# (1) If you don't want the module to depend on the exact compiler
-# version then use ocaml-find-requires.sh -c, but this is not something
-# you should do normally.
-#
-# (2) For any modules which you want to ignore, use '-i Modulename'.
-
-OCAMLOBJINFO=ocamlobjinfo
-TEMP=`getopt -o i:f: -n ocaml-find-provides.sh -- "$@"`
-if [ $? != 0 ]; then echo "ocaml-find-provides.sh: failed" >&2; exit 1; fi
-eval set -- "$TEMP"
-
-ignore_modules=nOTREAL
-
-while true; do
- case "$1" in
- -i) ignore_modules="$2 $ignore_modules"; shift 2;;
- -f) OCAMLOBJINFO="$2"; shift 2;;
- --) shift; break;;
- *) echo "ocaml-find-provides.sh: option error at $1"; exit 1;;
- esac
-done
-
-# Get the list of files.
-files=`sed "s/['\"]/\\\&/g"`
-
-# Get list of .cmi, .cmo and .cma files.
-files=`echo $files | tr '[:blank:]' '\n' | grep '\.cm[ioa]$'`
-
-if [ -z "$files" ]; then exit 0; fi
-
-# Get the list of modules exported by the files.
-modules=`$OCAMLOBJINFO $files |
- grep -E '(Unit|Module) name: ' |
- awk '{print $3}'`
-
-# Turn list of modules into a regexp that matches the module names.
-modules_re=`echo $modules | sed 's/ /|/g'`
-ignore_modules_re=`echo $ignore_modules | sed 's/ /|/g'`
-
-# Get a list of the modules these file(s) provide.
-$OCAMLOBJINFO $files |
-grep -Eo '[0-9a-f]{32}[[:space:]]+[A-Za-z0-9_]+' |
-grep -E '[0-9a-f]{32}[[:space:]]+'"($modules_re)\$" |
-while read md5sum module; do
- echo "ocaml($module) = $md5sum"
-done |
-grep -Ev "$ignore_modules_re" |
-sort -u
diff --git a/scripts/ocaml-find-requires.sh b/scripts/ocaml-find-requires.sh
deleted file mode 100644
index e10e6277a..000000000
--- a/scripts/ocaml-find-requires.sh
+++ /dev/null
@@ -1,68 +0,0 @@
-#!/bin/sh -
-# OCaml-specific "find-requires" for RPM.
-# By Richard W.M. Jones <rjones@redhat.com>
-# $Id: ocaml-find-requires.sh,v 1.5 2009/10/04 22:34:51 rjones Exp $
-
-#set -x
-
-# Usage:
-# (1) If you don't want the module to depend on the exact compiler
-# version then use ocaml-find-requires.sh -c, but this is not something
-# you should do normally.
-#
-# (2) For any modules which you want to ignore, use '-i Modulename'.
-
-OCAMLOBJINFO=ocamlobjinfo
-TEMP=`getopt -o ci:f: -n ocaml-find-requires.sh -- "$@"`
-if [ $? != 0 ]; then echo "ocaml-find-requires.sh: failed" >&2; exit 1; fi
-eval set -- "$TEMP"
-
-emit_compiler_version=yes
-ignore_modules=nOTREAL
-
-while true; do
- case "$1" in
- -c) emit_compiler_version=; shift;;
- -i) ignore_modules="$2 $ignore_modules"; shift 2;;
- -f) OCAMLOBJINFO="$2"; shift 2;;
- --) shift; break;;
- *) echo "ocaml-find-requires.sh: option error at $1"; exit 1;;
- esac
-done
-
-# Get the list of files.
-files=`sed "s/['\"]/\\\&/g"`
-
-# Use ordinary find-requires first.
-# echo $files | tr '[:blank:]' '\n' | /usr/lib/rpm/find-requires
-
-# Get list of .cmi, .cmo and .cma files.
-files=`echo $files | tr '[:blank:]' '\n' | grep '\.cm[ioa]$'`
-
-if [ -z "$files" ]; then exit 0; fi
-
-# Get the list of modules exported by the file(s).
-modules=`$OCAMLOBJINFO $files |
- grep -E '(Unit|Module) name: ' |
- awk '{print $3}'`
-
-# Turn list of modules into a regexp that matches the module names.
-modules_re=`echo $modules | sed 's/ /|/g'`
-ignore_modules_re=`echo $ignore_modules | sed 's/ /|/g'`
-
-# Get a list of the modules these file(s) depend on.
-$OCAMLOBJINFO $files |
-grep -Eo '[0-9a-f]{32}[[:space:]]+[A-Za-z0-9_]+' |
-grep -Ev '[0-9a-f]{32}[[:space:]]+'"($modules_re)\$" |
-while read md5sum module; do
- echo "ocaml($module) = $md5sum"
-done |
-grep -Ev "$ignore_modules_re" |
-grep -Ev "^ocaml\((Annot|Asttypes|Outcometree|Cmo_format|Parsetree)\) =" |
-sort -u
-
-if [ -n "$emit_compiler_version" ]; then
- # Every OCaml program depends on the version of the
- # runtime which was used to compile it.
- echo "ocaml(runtime) = `ocamlrun -version | awk '{print $NF}' | sed 's/\+.*//'`"
-fi
diff --git a/scripts/ocamldeps.sh b/scripts/ocamldeps.sh
new file mode 100644
index 000000000..aee72e3d4
--- /dev/null
+++ b/scripts/ocamldeps.sh
@@ -0,0 +1,243 @@
+#!/bin/bash
+# This is a helper for rpm which collects 'Provides' and 'Requires' information from OCaml files.
+# It reads a list of filenames from STDIN.
+# It expects as argument either '--provides|-P' or '--requires|-R'.
+# Additional optional arguments are:
+# -f "ocamlobjinfo command"
+# -c # ignored, recognized just for compat reasons
+# -i NAME # omit the Requires/Provides for this bytecode unit name
+# -x NAME # omit the Requires/Provides for this native unit name
+#
+# OCaml object files contain either bytecode or native code.
+# Each bytecode variant provides a certain interface, which is represented by a hash.
+# Each native variant provides a certain interface and a certain implementation, which are represented by hashes.
+# Each variant may also require a certain interface and/or implementation provided by other files.
+# The details for each file can be inspected with 'ocamlobjinfo'.
+#
+# Each file contains at least one module.
+# Information about each module follows after a line starting with "Name:" or "Unit name:":
+#
+# cma/cmi/cmo (bytecode):
+# Unit name: NAME
+# Interfaces imported:
+# HASH NAME
+# HASH NAME_FROM_OTHER_MODULE
+#
+# cmx/cmxa/cmxs (native):
+# Name: NAME
+# CRC of implementation: HASH
+# Interfaces imported:
+# HASH NAME
+# HASH NAME_FROM_OTHER_MODULE
+# Implementations imported:
+# HASH NAME_FROM_OTHER_MODULE
+#
+# The hash may contain just '-', in which case it is ignored.
+#
+# Output:
+# ocaml(NAME) = HASH # for interfaces (bytecode and native)
+# ocamlx(NAME) = HASH # for implementations (native)
+
+set -e
+#
+OCAMLOBJINFO=ocamlobjinfo
+rpm_prefix_interface='ocaml'
+rpm_prefix_implementation='ocamlx'
+#
+parse() {
+ local filename="$1"
+
+ ${OCAMLOBJINFO} "${filename}" | awk '
+ BEGIN {
+ debug=0
+ mode=ENVIRON["mode"]
+ RPM_BUILD_ROOT=ENVIRON["RPM_BUILD_ROOT"]
+ rpm_prefix_interface=ENVIRON["rpm_prefix_interface"]
+ rpm_prefix_implementation=ENVIRON["rpm_prefix_implementation"]
+ state="find"
+ unit=""
+
+ split(ENVIRON["ignore_implementation"], ignore_implementation_a)
+ for (i in ignore_implementation_a) {
+ val=ignore_implementation_a[i]
+ if (debug)
+ printf "INFO: ignore_implementation %s\n", val > "/dev/stderr"
+ ignore_implementation[val]=1
+ }
+ split(ENVIRON["ignore_interface"], ignore_interface_a)
+ for (i in ignore_interface_a) {
+ val=ignore_interface_a[i]
+ if (debug)
+ printf "INFO: ignore_interface %s\n", val > "/dev/stderr"
+ ignore_interface[val]=1
+ }
+ }
+
+ /^File / {
+ if (RPM_BUILD_ROOT != "" ) {
+ file=substr($2,length(RPM_BUILD_ROOT)+1)
+ } else {
+ file=$2
+ }
+ state="file"
+ next
+ }
+ /^Unit name:/ {
+ unit=$3
+ state="cma"
+ next
+ }
+ /^Name:/ {
+ unit=$2
+ state="cmx"
+ next
+ }
+
+ /^CRC of implementation:/ {
+ if (state == "cmx") {
+ if (ignore_implementation[unit] != "") {
+ if (ignore_implementation[unit] != "seen") {
+ printf "INFO: ignoring Provides %s(%s)=%s from %s\n", rpm_prefix_implementation, unit, $4, file > "/dev/stderr"
+ ignore_implementation[unit]="seen"
+ }
+ } else {
+ implementation_provides[unit]=$4
+ }
+ } else {
+ printf "WARN: state %s, expected cmx, got %s\n", state, $0 > "/dev/stderr"
+ }
+ state="crc"
+ next
+ }
+
+ /^Interfaces imported:/ {
+ state="interface"
+ next
+ }
+
+ /^Implementations imported:/ {
+ state="implementation"
+ next
+ }
+
+ /^\t/ {
+ if (state == "interface" && NF > 1 && match($1, "^-") == 0) {
+ if (unit == $2) {
+ if (ignore_interface[unit] != "") {
+ if (ignore_interface[unit] != "seen") {
+ printf "INFO: ignoring Provides %s(%s)=%s from %s\n", rpm_prefix_interface, unit, $1, file > "/dev/stderr"
+ ignore_interface[unit]="seen"
+ }
+ } else {
+ interface_provides[unit]=$1
+ }
+ } else {
+ if (ignore_interface[$2] != "") {
+ if (ignore_interface[$2] != "seen") {
+ printf "INFO: ignoring Requires %s(%s)=%s from %s\n", rpm_prefix_interface, $2, $1, file > "/dev/stderr"
+ ignore_interface[$2]="seen"
+ }
+ } else {
+ interface_requires[$2]=$1
+ }
+ }
+ next
+ } else if (state == "implementation" && NF > 1 && match($1, "^-") == 0) {
+ if (unit == $2) {
+ if (ignore_implementation[unit] != "") {
+ if (ignore_implementation[unit] != "seen") {
+ printf "INFO: ignoring Provides %s(%s)=%s from %s\n", rpm_prefix_implementation, unit, $1, file > "/dev/stderr"
+ ignore_implementation[unit]="seen"
+ }
+ } else {
+ implementation_provides[unit]=$1
+ }
+ } else {
+ if (ignore_implementation[$2] != "") {
+ if (ignore_implementation[$2] != "seen") {
+ printf "INFO: ignoring Requires %s(%s)=%s from %s\n", rpm_prefix_implementation, $2, $1, file > "/dev/stderr"
+ ignore_implementation[$2]="seen"
+ }
+ } else {
+ implementation_requires[$2]=$1
+ }
+ }
+ next
+ } else {
+ next
+ }
+ }
+ /^.*/ {
+ state="find"
+ }
+
+ END {
+ if (mode == "provides") {
+ for (i in interface_provides) {
+ printf "%s(%s) = %s\n", rpm_prefix_interface, i, interface_provides[i]
+ }
+ for (i in implementation_provides) {
+ printf "%s(%s) = %s\n", rpm_prefix_implementation, i, implementation_provides[i]
+ }
+ }
+ if (mode == "requires") {
+ for (i in interface_requires) {
+ printf "%s(%s) = %s\n", rpm_prefix_interface, i, interface_requires[i]
+ }
+ for (i in implementation_requires) {
+ printf "%s(%s) = %s\n", rpm_prefix_implementation, i, implementation_requires[i]
+ }
+ }
+ }
+ '
+}
+#
+#
+usage() {
+ echo >&2 "Usage: ${0##*/} -provides|-requires [-f 'ocamlobjinfo cmd']"
+}
+#
+mode=
+ignore_implementation_a=()
+ignore_interface_a=()
+while test "$#" -gt 0
+do
+ : "${1}" "${2}"
+ case "${1}" in
+ -P|--provides) mode='provides' ;;
+ -R|--requires) mode='requires' ;;
+ -i) ignore_interface_a+=("$2") ; shift ;;
+ -x) ignore_implementation_a+=("$2") ; shift ;;
+ -f) OCAMLOBJINFO="$2"; shift ;;
+ -h|--help) usage ; exit 0 ;;
+ -c) ;; # ignored
+ --) break ;;
+ *) usage ; exit 1 ;;
+ esac
+ shift
+done
+if test -z "${mode}"
+then
+ usage
+ exit 1
+fi
+#
+export rpm_prefix_interface
+export rpm_prefix_implementation
+export mode
+export ignore_implementation="${ignore_implementation_a[@]}"
+export ignore_interface="${ignore_interface_a[@]}"
+#
+while read filename
+do
+ case "${filename}" in
+ *.cma) parse "${filename}" ;;
+ *.cmi) parse "${filename}" ;;
+ *.cmo) parse "${filename}" ;;
+ *.cmx) parse "${filename}" ;;
+ *.cmxa) parse "${filename}" ;;
+ *.cmxs) parse "${filename}" ;;
+ *) continue ;;
+ esac
+done
+# vim: tw=666 ts=2 shiftwidth=2 et