diff options
-rw-r--r-- | fileattrs/ocaml.attr | 7 | ||||
-rw-r--r-- | scripts/Makefile.am | 4 | ||||
-rw-r--r-- | scripts/ocaml-find-provides.sh | 56 | ||||
-rw-r--r-- | scripts/ocaml-find-requires.sh | 68 | ||||
-rw-r--r-- | scripts/ocamldeps.sh | 243 |
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 |