retitle 528367 new Lintian checks for OCaml packages tags 528367 + patch thanks
Stephane Glondu a écrit : > It would be nice to emit a Lintian error in the following circumstances: > [...] There are of course many other checks that we (OCaml maintainers) would like Lintian to perform. Attached are some of them. I am sending this right now to get some feedback from the Lintian maintainers about the coding style, the structure of the code, etc. Cheers, -- Stéphane
From cd01e78475309be7e411ffe94835a024861b0de7 Mon Sep 17 00:00:00 2001 From: Stephane Glondu <st...@glondu.net> Date: Mon, 20 Jul 2009 10:01:41 +0200 Subject: [PATCH] Add ar-info collection script To detect dangling .cmx (#528367), we need to know the list of files inside .a files. This information might useful for other, not OCaml-related, checks. Signed-off-by: Stephane Glondu <st...@glondu.net> --- collection/ar-info | 54 +++++++++++++++++++++++++++++++++++++++++++++++ collection/ar-info.desc | 7 ++++++ 2 files changed, 61 insertions(+), 0 deletions(-) create mode 100755 collection/ar-info create mode 100644 collection/ar-info.desc diff --git a/collection/ar-info b/collection/ar-info new file mode 100755 index 0000000..c88ce25 --- /dev/null +++ b/collection/ar-info @@ -0,0 +1,54 @@ +#!/usr/bin/perl -w +# ar-info -- lintian collection script +# +# Copyright © 2009 Stéphane Glondu +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +use strict; + +($#ARGV == 1) or fail("syntax: ar-info <pkg> <type>"); +my $pkg = shift; +my $type = shift; + +-f "fields/source" or fail("ar-info invoked in wrong directory"); + +unlink("ar-info"); +chdir("unpacked") + or fail("cannot chdir to unpacked directory: $!"); + +open(INDEX, '<', "../index") + or fail("cannot open index file: $!"); +open(OUT, '>', "../ar-info"); + +while (<INDEX>) { + chomp; + next unless /\.a$/; + my $file = (split(" ", $_, 6))[5]; + open(OBJS, '-|', "ar t $file") + or fail("cannot read file: $!"); + print OUT "$file:"; + while (<OBJS>) { + chomp; + print OUT " $_"; + } + close(OBJS); + print OUT "\n"; +} + +close(INDEX); +close(OUT); diff --git a/collection/ar-info.desc b/collection/ar-info.desc new file mode 100644 index 0000000..eaecfcf --- /dev/null +++ b/collection/ar-info.desc @@ -0,0 +1,7 @@ +Collector-Script: ar-info +Author: Stéphane Glondu <st...@glondu.net> +Info: This script runs the "ar t" command over all .a files of package. +Type: binary +Unpack-Level: 2 +Version: 1 +Order: 1 -- 1.6.3.3
From 097ef9c668da753f6ea0636f9669d7285cab2412 Mon Sep 17 00:00:00 2001 From: Stephane Glondu <st...@glondu.net> Date: Mon, 20 Jul 2009 10:01:31 +0200 Subject: [PATCH] Add various checks about OCaml binary packages New lintian check script checks/ocaml{,.desc}: * ocaml-dangling-cmx, ocaml-dangling-cmxa (Closes: #528367) * ocaml-dangling-cmi * ocaml-dangling-cmxs * ocaml-stray-cmo * ocaml-dev-file-not-in-usr-lib-ocaml * ocaml-dev-file-in-nondev-package * ocaml-meta-without-suggestion-to-findlib Signed-off-by: Stephane Glondu <st...@glondu.net> --- checks/ocaml | 185 +++++++++++++++++++++++++++++++++++++++++++++++++++++ checks/ocaml.desc | 65 +++++++++++++++++++ 2 files changed, 250 insertions(+), 0 deletions(-) create mode 100644 checks/ocaml create mode 100644 checks/ocaml.desc diff --git a/checks/ocaml b/checks/ocaml new file mode 100644 index 0000000..2c62817 --- /dev/null +++ b/checks/ocaml @@ -0,0 +1,185 @@ +# ocaml -- lintian check script -*- perl -*- +# +# Copyright © 2009 Stéphane Glondu +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, you can find it on the World Wide +# Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free +# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, +# MA 02110-1301, USA. + +package Lintian::ocaml; +use strict; +use Tags; +use File::Basename; + +sub run { + +my $pkg = shift; +my $type = shift; +my $info = shift; + +# Collect information about .a files from ar-info dump +my %provided_o; +open ARINFO, "ar-info"; +while (<ARINFO>) { + chomp; + if (/^\.\/([^:]+): (.*)$/) { + my $filename = $1; + my $dirname = dirname($filename); + foreach (split(" ", $2)) { + # Note: a .o may be legitimately in several different .a + $provided_o{"$dirname/$_"} = $filename; + } + } +} +close ARINFO; + +# is it a library package? +my $is_lib_package = 0; +if ($pkg =~ /^lib/) { + $is_lib_package = 1; +} + +# is it a development package? +my $is_dev_package = 0; +if ($pkg =~ /(-dev|^camlp[45](-extra)?|^ocaml(-nox|-interp|-compiler-libs)?)$/) { + $is_dev_package = 1; +} + +# for libraries outside /usr/lib/ocaml +my $outside_number = 0; +my $outside_prefix; + +# dangling .cmi files (we show only $max_cmi of them) +my $cmi_number = 0; +my $max_cmi = 3; + +# dev files in nondev package +my $dev_number = 0; +my $dev_prefix; + +# does the package provide a META file? +my $has_meta = 0; + +foreach my $file (sort keys %{$info->file_info}) { + my $fileinfo = $info->file_info->{$file}; + + # For each .cmxa file, there must be a matching .a file (#528367) + $_ = $file; + if (s/\.cmxa$/.a/ && !(exists $info->file_info->{$_})) { + tag "ocaml-dangling-cmxa", $file; + } + + # For each .cmxs file, there must be a matching .cma or .cmo file + # (at least, in library packages) + if ($is_lib_package) { + $_ = $file; + if (s/\.cmxs$/.cm/ + && !(exists $info->file_info->{"${_}a"}) + && !(exists $info->file_info->{"${_}o"})) { + tag "ocaml-dangling-cmxs", $file; + } + } + + # The .cmx counterpart: for each .cmx file, there must be a + # matching .o file, which can be there by itself, or embedded in a + # .a file in the same directory + $_ = $file; + if (s/\.cmx$/.o/ + && !(exists $info->file_info->{$_}) + && !(exists $provided_o{$_})) { + tag "ocaml-dangling-cmx", $file; + } + + # $somename.cmi should be shipped with $somename.mli or $somename.ml + $_ = $file; + if ($is_dev_package && s/\.cmi$/.ml/ + && !(exists $info->file_info->{"${_}i"}) + && !(exists $info->file_info->{$_})) { + $cmi_number++; + if ($cmi_number <= $max_cmi) { + tag "ocaml-dangling-cmi", $file; + } + } + + # non-dev packages should not ship .cmi, .cmx or .cmxa files + if ($file =~ m/\.cm(i|xa?)$/) { + $dev_number++; + if (defined $dev_prefix) { + chop $dev_prefix while ($file !~ m...@^$dev_prefix@); + } else { + $dev_prefix = $file; + } + } + + # $somename.cmo should usually not be shipped with $somename.cma + $_ = $file; + if (s/\.cma$/.cmo/ && exists $info->file_info->{$_}) { + tag "ocaml-stray-cmo", $file; + } + + # development files outside /usr/lib/ocaml (.cmi, .cmx, .cmxa) + # .cma, .cmo and .cmxs are excluded because they can be plugins + if ($file =~ m/\.cm(i|xa?)$/ && $file !~ m...@^usr/lib/ocaml/@) { + $outside_number++; + if (defined $outside_prefix) { + chop $outside_prefix while ($file !~ m...@^$outside_prefix@); + } else { + $outside_prefix = $file; + } + } + + # if there is a META file, ocaml-findlib should be at least + # suggested + $has_meta = 1 if $file =~ m@/META(\..*)?$@; + +} + +if ($is_dev_package) { + # summary about .cmi files + if ($cmi_number > $max_cmi) { + tag "ocaml-dangling-cmi", ($cmi_number-$max_cmi), "more file(s) not shown"; + } + # summary about /usr/lib/ocaml + if ($outside_number) { + $outside_prefix = dirname($outside_prefix); + tag "ocaml-dev-file-not-in-usr-lib-ocaml", "$outside_number file(s) in /$outside_prefix"; + } + if ($has_meta) { + my $findlib = 0; + for my $field (qw(depends recommends suggests)) { + if (defined $info->field($field)) { + $_ = $info->field($field); + $findlib = 1 if /ocaml-findlib/; + } + } + tag "ocaml-meta-without-suggestion-to-findlib" unless $findlib; + } +} else { + # summary about dev files + if ($dev_number > 0) { + $dev_prefix = dirname($dev_prefix); + tag "ocaml-dev-file-in-nondev-package", "$dev_number file(s) in /$dev_prefix"; + } +} + +} + +1; + +# Local Variables: +# indent-tabs-mode: nil +# cperl-indent-level: 4 +# End: +# vim: ts=8 sw=4 noet syntax=perl diff --git a/checks/ocaml.desc b/checks/ocaml.desc new file mode 100644 index 0000000..8d21a50 --- /dev/null +++ b/checks/ocaml.desc @@ -0,0 +1,65 @@ +Check-Script: ocaml +Author: Stephane Glondu <st...@glondu.net> +Abbrev: ocaml +Type: binary +Unpack-Level: 1 +Info: This looks for common mistakes in OCaml binary packages. +Needs-Info: file-info, ar-info + +Tag: ocaml-dangling-cmxa +Severity: serious +Certainty: certain +Info: This package provides a .cmxa library without its implementation + (.a static library). + +Tag: ocaml-dangling-cmx +Severity: serious +Certainty: certain +Info: This package provides a .cmx module without its implementation + (.o object file which may be embedded in a .a static library + installed in the same directory). + +Tag: ocaml-dangling-cmxs +Severity: normal +Certainty: possible +Info: This package seems to be a library package, and provides a + native plugin (.cmxs). If the plugin is meant to be used as a + library for other plugins, it should be shipped as bytecode + (.cma or .cmo) as well. + +Tag: ocaml-dev-file-not-in-usr-lib-ocaml +Severity: pedantic +Certainty: possible +Info: This development package installs OCaml development files (.cmi, + .cmx or .cmxa) outside /usr/lib/ocaml. Such files are used only by + compilation and should be in a subdirectory of OCaml standard library + path. + +Tag: ocaml-stray-cmo +Severity: normal +Certainty: wild-guess +Info: This package installs a .cma file and a .cmo file with the same + base name. Most of the time, the module provided by the .cmo file is + also linked in the .cma file, so the .cmo file is useless. + +Tag: ocaml-dangling-cmi +Severity: wishlist +Certainty: possible +Info: This package installs a compiled interface (.cmi) without its + text version (.mli). The text version should also be installed for + documentation purpose. If the module involved doesn't have a .mli, + its source code (.ml) should be installed instead. + +Tag: ocaml-dev-file-in-nondev-package +Severity: pedantic +Certainty: possible +Info: This package doesn't appear to be a development package, but + installs OCaml development files (.cmi, .cmx or .cmxa). These files + should be moved to a development package. + +Tag: ocaml-meta-without-suggestion-to-findlib +Severity: pedantic +Certainty: certain +Info: This development package installs a META file, but doesn't + depend on ocaml-findlib. Libraries with META file are easier to use + with findlib; the package should at least suggest ocaml-findlib. -- 1.6.3.3