I've tried following some other examples and have something like:
{
package Foo::Bar;
}
{
package Foo::Baz;
use Foo::Bar;
}
use Foo::Baz;
# some more code
# Fails with: Can't locate Foo/Bar.pm in @INC
My real-world example is I'd like to bundle/concat https://github.com/TeX-Live/texlive-source/blob/trunk/texk/texlive/linked_scripts/texlive/fmtutil.pl along with its dependencies https://github.com/TeX-Live/installer/blob/master/tlpkg/TeXLive/TLConfig.pm and https://github.com/TeX-Live/installer/blob/master/tlpkg/TeXLive/TLUtils.pm into a single file.
Thank you!
The problem is that Perl doesn't know the module is already loaded because you haven't faithfully replicated the loading process. Specifically, you didn't modify %INC
.
You could also have problems from not loading the module at compile-time. This could be achieved using a BEGIN
block.
To inline a module, add the following to the start of your script:
BEGIN {
# Insert module here.
$INC{ ( __PACKAGE__ =~ s{::}{/}rg ) . ".pm" } = 1;
}
So if you had
# script.pl
use strict;
use Foo::Baz;
# ...
# Foo/Bar.pm
package Foo::Bar;
use strict;
# ...
1;
# Foo/Baz.pm
package Foo::Baz;
use strict;
use Foo::Bar;
# ...
1;
You'd end up with
BEGIN {
# Foo/Bar.pm
package Foo::Bar;
use strict;
# ...
$INC{ ( __PACKAGE__ =~ s{::}{/}rg ) . ".pm" } = 1;
}
BEGIN {
# Foo/Baz.pm
package Foo::Baz;
use strict;
use Foo::Bar;
# ...
$INC{ ( __PACKAGE__ =~ s{::}{/}rg ) . ".pm" } = 1;
}
# script.pl
use strict;
use Foo::Baz;
# ...
Note the above isn't 100% equivalent to inlining the modules. For example, the equivalent of
use 5.012;
use open ":std", ":encoding(UTF-8)";
use Some::Module;
would actually be
# Non-lexical effects
BEGIN {
require 5.012;
binmode(STDIN, ":encoding(UTF-8)");
binmode(STDOUT, ":encoding(UTF-8)");
binmode(STDERR, ":encoding(UTF-8)");
}
BEGIN {
package Some::Module;
...
$INC{"Some/Module.pm"} = 1;
}
# Lexical effects
use 5.012;
use open ":encoding(UTF-8)";
To properly inline a module, it would be better to use an @INC
hook. Using the files from the first approach, one would end up with
BEGIN {
my %modules = (
"Foo/Bar.pm" => <<'__EOI__',
# Foo/Bar.pm
package Foo::Bar;
use strict;
# ...
1;
__EOI__
"Foo/Baz.pm" => <<'__EOI__',
# Foo/Baz.pm
package Foo::Baz;
use strict;
use Foo::Bar;
# ...
1;
__EOI__
);
unshift @INC, sub {
my $module = $modules{$_[1]}
or return;
return \$module;
};
}
# script.pl
use strict;
use Foo::Baz;
# ...
App::FatPacker can be used to inline modules this way.
The line numbers in warnings and errors will be the line numbers of the original file. a #line
directive added to the inlined module would adjust that.