jordansissel/fpm · error · FPM::InvalidPackageConfiguration

I don't know how to build #{name}. No Makefile.PL nor Build.

Error message

I don't know how to build #{name}. No Makefile.PL nor Build.PL found

What it means

fpm's cpan source package only knows two Perl build systems: Module::Build (Build.PL) and ExtUtils::MakeMaker (Makefile.PL). After downloading and extracting the distribution tarball from CPAN/metacpan, it checks for those two files in the extracted root; if neither exists it raises FPM::InvalidPackageConfiguration with this message. The package name in the message is the CPAN distribution being built.

Source

Thrown at lib/fpm/package/cpan.rb:262

                     "-Mlocal::lib=#{build_path("cpan")}",
                     "Makefile.PL", "PREFIX=#{prefix}", "LIB=#{perl_lib_path}",
                     # Empty install_base to avoid local::lib being used.
                     "INSTALL_BASE=")
        else
          safesystem(attributes[:cpan_perl_bin],
                     "-Mlocal::lib=#{build_path("cpan")}",
                     "Makefile.PL", "PREFIX=#{prefix}",
                     # Empty install_base to avoid local::lib being used.
                     "INSTALL_BASE=")
        end
        make = [ "env", "PERL5LIB=#{build_path("cpan/lib/perl5")}", "make" ]
        safesystem(*make)
        safesystem(*(make + ["test"])) if attributes[:cpan_test?]
        safesystem(*(make + ["DESTDIR=#{staging_path}", "install"]))


      else
        raise FPM::InvalidPackageConfiguration,
          "I don't know how to build #{name}. No Makefile.PL nor " \
          "Build.PL found"
      end

      # Fix any files likely to cause conflicts that are duplicated
      # across packages.
      # https://github.com/jordansissel/fpm/issues/443
      # https://github.com/jordansissel/fpm/issues/510
      glob_prefix = attributes[:cpan_perl_lib_path] || prefix
      ::Dir.glob(File.join(staging_path, glob_prefix, "**/perllocal.pod")).each do |path|
        logger.debug("Removing useless file.",
                      :path => path.gsub(staging_path, ""))
        File.unlink(path)
      end

      # Remove useless .packlist files and their empty parent folders
      # https://github.com/jordansissel/fpm/issues/1179
      ::Dir.glob(File.join(staging_path, glob_prefix, "**/.packlist")).each do |path|

View on GitHub (pinned to b6d77ba72a)

Solutions

  1. Download the tarball manually and inspect it (tar tzf Foo-1.00.tar.gz) to confirm whether Build.PL or Makefile.PL actually exists at the root
  2. Retry without --version (or with a different --version) so metacpan resolves a normal, complete release
  3. If the module has no supported build script, build/install it yourself (perl Makefile.PL && make install DESTDIR=...) and package the result with fpm -s dir -t deb
  4. Point --cpan-mirror at a complete mirror such as http://www.cpan.org/ to rule out a truncated download

Example fix

# before
fpm -s cpan -t deb Some::Module --version 0.01   # 0.01 tarball lacks build scripts

# after
fpm -s cpan -t deb Some::Module                  # let metacpan pick a complete release
# or package a manual install:
#   perl Makefile.PL && make && make install DESTDIR=/tmp/root
fpm -s dir -t deb -n some-module -v 1.00 /tmp/root
Defensive patterns

Strategy: validation

Validate before calling

# Pre-check the release tarball fpm will fetch, before invoking the CPAN source
require 'net/http'
require 'json'

url = URI('https://fastapi.metacpan.org/v1/release/_search?_source=download_url')
body = { query: { term: { name: "#{dist}-#{version}" } } }.to_json
resp = Net::HTTP.post(url, body, 'Content-Type' => 'application/json')
raise 'metacpan unreachable' unless resp.code == '200'

dl = JSON.parse(resp.body)['hits']['hits'][0]['_source']['download_url']
# fpm extracts the tarball and needs Build.PL or Makefile.PL at the root;
# inspecting the tarball member list locally requires downloading it first:
system("curl -sL http://www.cpan.org/#{dl} -o /tmp/pkg.tar.gz")
files = `tar tzf /tmp/pkg.tar.gz`.split("\n")
has_build = files.any? { |f| f =~ /(Build\.PL|Makefile\.PL)$/ }
abort 'no Build.PL/Makefile.PL: package manually with -s dir' unless has_build

Try / catch

begin
  FPM::Package::CPAN.new.input(module_name)
rescue FPM::InvalidPackageConfiguration => e
  # message matches /No Makefile.PL nor Build.PL/
  warn "#{module_name} has no supported build script; falling back to -s dir"
  build_and_package_manually(module_name)
end

Prevention

When it happens

Trigger: Running fpm -s cpan -t deb Some::Module (or the API equivalent FPM::Package::CPAN#input) where the resolved release tarball contains neither Build.PL nor Makefile.PL at its root, e.g. the build files live in a subdirectory or the release ships without them. Also triggered when --version pins a release whose tarball layout is unusual or the mirror served a truncated archive.

Common situations: Packaging a distribution built with an exotic toolchain or a hand-assembled release missing build scripts; a CPAN mirror serving partial tarballs; a name/version combination resolving to a broken release on metacpan; the tarball extracting into a nested directory so the files are not found in cwd.

Related errors


AI-assisted analysis of jordansissel/fpm@b6d77ba72a (2026-08-21). Data as JSON: /api/errors/4bc1eeebaf01d8ab. Report an issue: GitHub.