1

I'm researching about how to package some of my Perl apps and better manage their dependencies to make distribution easier for me and my customers, which most likely doesn't include uploading to CPAN at all. Instead, I would provide custom repos if necessary or, more likely, access to SCMs like Subversion.

CPAN::Meta::Spec seems to provide what I need to describe my apps, their dependencies and even where to get them from, but what I'm wondering is about the level of detail of pre-requisites. The spec contains the following sentence:

The set of relations must be specified as a Map of package names to version ranges.

Requiring packages seems a little too low level for my needs, I would prefer requiring distributions instead. Pretty much the level (from my understanding) tools like Maven and Gradle work at, e.g. Apache Commons Lang vs. Apache Commons IO etc. instead of individual classes like org.apache.commons.lang3.AnnotationUtils or org.apache.commons.io.ByteOrderMark. OTOH, the example in the docs contains the following lines:

requires => {
  'perl'          => '5.006',
  'File::Spec'    => '0.86',
  'JSON'          => '2.16',
},

The line containing perl doesn't look like a package to me and I didn't find some package perl or perl.pm anywhere on my system. Seems to me like that is handled differently to the other things of the example.

I have a system wide folder containing e.g. some utility packages, which seems comparable to some abstract perl to me. That folder should get defined as one distribution, maintain a version number for all of the packages in that folder and therefore should allow other apps to require that whole thing. If I understand the docs correctly, I would need to create not only the META.yml in the folder, but additionally some e.g. sysutils.pm containing package sysutils; and defining some version.

Is there some way to avoid creating that file and really require the distribution itself only?

The META.yml already contains a name and version on it's own, so looks like some abstract thing one could require in theory. I don't see the need of adding an additional .pm-file representing the distribution itself only to allow require to work. It wouldn't contain any business logic in my case.

Thanks!

Thorsten Schöning
  • 3,501
  • 2
  • 25
  • 46

2 Answers2

3

That's really not what you want to do. You want to pre-req what you actually require. So, for example, if you need File::Spec, that's what you need, regardless of whether it comes from perl core or from a separate CPAN distribution.

I've seen cases where certain modules have moved from CPAN to core, or vice versa. By requiring the module directly, you don't need to ship new releases of your dependent distributions simply because someone you depend on changed their method of distribution.

I've also seen cases where certain modules are split off from their original distributions when it was determined they were valuable as standalone modules. Depending on the module means that you no longer drag in a bunch of other modules for a simple dependency.

What you're more or less looking for is akin to the Task::* modules. No real logic in most of them, just a list of further dependencies.

Tanktalus
  • 21,664
  • 5
  • 41
  • 68
  • OTOH, it doesn't make much sense to me to maintain individual required packages at two places, one being the package actually requiring and the other `META.yml`. In the latter case with no context or hierarchy showing why it is required and can be easily forgotten to maintain. So I would I need some automated process to maintain those things, making everything more complicated, while working on the level of a distribution with different repos seems to work pretty good for e.g. Maven and Gradle. – Thorsten Schöning Feb 01 '19 at 17:32
  • It only works until it doesn't anymore. And there are CPAN tools for maintaining META.yml - I've almost never edited that myself, relying on Module::Build or similar to do it for me as part of the `dist` action. – Tanktalus Feb 01 '19 at 17:34
  • `Module::Build` is considered a failed experiment by some people as well, Maven and Gradle work for pretty large projects and automated tools e.g. can't be used easily with things like different features with different requirements within one app. I have such apps requiring different 3rd party libs depending on runtime configuration, e.g. GD or OpenOffice-Libs or ... https://stackoverflow.com/questions/30765522/cpan-module-prereqs#comment49583542_30765614 – Thorsten Schöning Feb 01 '19 at 17:36
  • In the end, I can always switch to individual packages if it doesn't work on a distribution level anymore, but not the other way around if CPAN::Meta::Spec simply doesn't support it. Hence my question. – Thorsten Schöning Feb 01 '19 at 17:39
  • Module::Build isn't the only one that can update META.yml for you. It's just the one I remember off the top of my head. – Tanktalus Feb 01 '19 at 17:42
  • @ThorstenSchöning Every authoring tool maintains META.json for you, including [ExtUtils::MakeMaker](https://perldoc.pl/ExtUtils::MakeMaker#make-distdir). You should not be caring about META.yml or META.json manually, ever, but instead [specifying your prereqs for your authoring tool](http://blogs.perl.org/users/neilb/2017/05/specifying-dependencies-for-your-cpan-distribution.html). META.yml is also the outdated format, though you should include both for compatibility. – Grinnz Feb 01 '19 at 21:47
  • @ThorstenSchöning If you want a system to specify prereqs that is independent of authoring tools, look into [cpanfile](http://metacpan.org/pod/cpanfile), which can be used by several authoring tools and also by [cpanm](http://metacpan.org/pod/cpanm), [Carton](http://metacpan.org/pod/Carton), and on its own via [Module::CPANfile](https://metacpan.org/pod/Module::CPANfile). But it will still be package-based. – Grinnz Feb 01 '19 at 22:08
  • @ThorstenSchöning Also something like [scan-prereqs-cpanfile](https://metacpan.org/pod/scan-prereqs-cpanfile) may be of interest, though prereq scanning is an imperfect art so it can be fooled. – Grinnz Feb 01 '19 at 22:29
0

The Perl dependency system works entirely on package names, on multiple levels. When a CPAN distribution is uploaded, each package within is indexed by PAUSE, which also checks if the uploader has permissions for that package and that the package has a newer version than the currently indexed package. None of these checks care about the distribution as a whole (though the indexer does do other checks at that level).

Then, when a CPAN client sees a dependency, or you tell it to install something, it checks the index for that package name, which tells it what distribution release to install. If it depends on a certain version, that is checked against the $VERSION declared in that package if you have it installed; whereas once a distribution is installed, its "version" is no longer tracked. The distribution level is almost entirely meaningless except that it is what is ultimately downloaded and installed to satisfy these dependencies. This is important, because modules can and do move between distributions, maintaining their version increments, and the package index will always tell you which distribution to get the version you need.

As you noticed, the perl dependency is weird. It's a special case that has been there forever, as a convention to declare what version of Perl you require, you declare a runtime requirement of perl. It is not an indexed module, and every CPAN client and other consumer of CPAN metadata special cases this to either ignore it or treat it as a minimum Perl version, rather than something that can be installed. There's no way to extend this to work for distributions in general, and it would be a bad idea to try.

As an additional note, the CPAN meta spec is a specification for the file named META.json included in CPAN distributions (META.yml is the legacy version), but this file is automatically generated by your authoring tool. It should never be manually created, though you may have your authoring tool manually add certain keys (in which case reading the spec is important), including prereqs. See neilb's blog post for how to specify dependencies for various authoring tools, which will then transpose these into the generated META file, and also how to use cpanfiles to specify dependencies in general.

Grinnz
  • 9,093
  • 11
  • 18
  • The mentioned blog post either writes `META.*-structures manually in some build tool, where I don't see the need to use that tool at all, or suggests tools others see as deprecated already or mentions tools itself saying those are not recommended anymore. `cpanfile` doesn't seem to provide any benefit to `META.*` as well, it doesn't e.g. seem to handle different repos as install source, preferable defined per distribution like is the case with Maven and Gradle. – Thorsten Schöning Feb 02 '19 at 08:48
  • I've started my research with `cpanfile`, which lead me to `CPAN::Meta::Spec` and all those mentioned build/authoring tools I came across either were not recommended anymore or simply didn't fit my needs regarding repo definitions, distinguishing optional features and their requirements properly within apps etc. This whole topic currently seems like a lot of redundant approaches and mixing high with too low levels to me. I more or less seem to only need an approach like Maven or Gradle. – Thorsten Schöning Feb 02 '19 at 08:51