diff --git a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java
index 25a612044..13474ab53 100644
--- a/src/main/java/org/perlonjava/app/cli/ArgumentParser.java
+++ b/src/main/java/org/perlonjava/app/cli/ArgumentParser.java
@@ -43,31 +43,37 @@ public static CompilerOptions parseArguments(String[] args) {
// If no code was provided and no filename, try reading from stdin
if (parsedArgs.code == null) {
- try {
- // Try to read from stdin - this will work for pipes, redirections, and interactive input
- StringBuilder stdinContent = new StringBuilder();
- BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
-
- // Check if we're reading from a pipe/redirection vs interactive terminal
- boolean isInteractive = System.console() != null;
-
- if (isInteractive) {
- // Interactive mode - prompt the user and read until EOF (Ctrl+D)
- System.err.println("Enter Perl code (press Ctrl+D when done):");
- }
+ // Check if we're reading from a pipe/redirection vs interactive terminal
+ boolean isInteractive = System.console() != null;
+
+ // If interactive and we have -M modules, just run them without waiting for stdin
+ // This matches Perl behavior: perl -MModule=args runs the module and exits
+ if (isInteractive && !parsedArgs.moduleUseStatements.isEmpty()) {
+ parsedArgs.code = ""; // Empty code, just run the use statements
+ } else {
+ try {
+ // Try to read from stdin - this will work for pipes, redirections, and interactive input
+ StringBuilder stdinContent = new StringBuilder();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
+
+ if (isInteractive) {
+ // Interactive mode - prompt the user and read until EOF (Ctrl+D)
+ System.err.println("Enter Perl code (press Ctrl+D when done):");
+ }
- // Read from stdin regardless of whether it's interactive or not
- String line;
- while ((line = reader.readLine()) != null) {
- stdinContent.append(line).append("\n");
- }
+ // Read from stdin regardless of whether it's interactive or not
+ String line;
+ while ((line = reader.readLine()) != null) {
+ stdinContent.append(line).append("\n");
+ }
- if (stdinContent.length() > 0) {
- parsedArgs.code = stdinContent.toString();
- parsedArgs.fileName = "-"; // Indicate that code came from stdin
+ if (stdinContent.length() > 0) {
+ parsedArgs.code = stdinContent.toString();
+ parsedArgs.fileName = "-"; // Indicate that code came from stdin
+ }
+ } catch (IOException e) {
+ // If we can't read from stdin, continue with normal error handling
}
- } catch (IOException e) {
- // If we can't read from stdin, continue with normal error handling
}
}
diff --git a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java
index 26f9e4a5e..f3ab33410 100644
--- a/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java
+++ b/src/main/java/org/perlonjava/backend/bytecode/BytecodeCompiler.java
@@ -3911,14 +3911,18 @@ void compileVariableReference(OperatorNode node, String op) {
// This will add the current package if no package is specified
subName = NameNormalizer.normalizeVariableName(subName, getCurrentPackage());
- // Allocate register for code reference
+ // Cache the RuntimeScalar code reference at compile time.
+ // This matches Perl's behavior where the CV (code value) is cached
+ // in the compiled bytecode, surviving stash entry deletion.
+ RuntimeScalar codeRef = GlobalVariable.getGlobalCodeRef(subName);
+
+ // Allocate register and load from constant pool
int rd = allocateOutputRegister();
- int nameIdx = addToStringPool(subName);
+ int constIdx = addToConstantPool(codeRef);
- // Emit LOAD_GLOBAL_CODE
- emit(Opcodes.LOAD_GLOBAL_CODE);
+ emit(Opcodes.LOAD_CONST);
emitReg(rd);
- emit(nameIdx);
+ emit(constIdx);
lastResultReg = rd;
} else if (node.operand instanceof BlockNode || node.operand instanceof OperatorNode) {
diff --git a/src/main/java/org/perlonjava/backend/jvm/Dereference.java b/src/main/java/org/perlonjava/backend/jvm/Dereference.java
index 8e8287747..1c8c26c38 100644
--- a/src/main/java/org/perlonjava/backend/jvm/Dereference.java
+++ b/src/main/java/org/perlonjava/backend/jvm/Dereference.java
@@ -365,14 +365,69 @@ static void handleArrayElementOperator(EmitterVisitor emitterVisitor, BinaryOper
}
}
if (node.left instanceof ListNode list) { // ("a","b","c")[2]
- // transform to: ["a","b","c"]->[2]
- BinaryOperatorNode refNode = new BinaryOperatorNode("->",
- new ArrayLiteralNode(list.elements, list.getIndex()),
- node.right, node.tokenIndex);
- refNode.accept(emitterVisitor);
+ // Use proper list slice semantics: evaluate list, then slice
+ // This differs from array dereference because empty list returns empty, not undef
+ if (CompilerOptions.DEBUG_ENABLED) emitterVisitor.ctx.logDebug("visit(BinaryOperatorNode) (list)[indices] - list slice");
+
+ // Evaluate the list
+ list.accept(emitterVisitor.with(RuntimeContextType.LIST));
+
+ // Convert to RuntimeList if not already (handles RuntimeScalar case)
+ emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "org/perlonjava/runtime/runtimetypes/RuntimeBase",
+ "getList",
+ "()Lorg/perlonjava/runtime/runtimetypes/RuntimeList;",
+ false);
+
+ // Save the list to a local variable before evaluating indices.
+ // This is necessary because indices may contain function calls that
+ // generate complex bytecode with exception handlers, and the JVM
+ // verifier requires consistent stack heights at merge points.
+ int listVar = emitterVisitor.ctx.symbolTable.allocateLocalVariable();
+ emitterVisitor.ctx.mv.visitVarInsn(Opcodes.ASTORE, listVar);
+
+ // Evaluate the indices
+ ListNode indices = ((ArrayLiteralNode) node.right).asListNode();
+ indices.accept(emitterVisitor.with(RuntimeContextType.LIST));
+
+ // Save indices to local variable too
+ int indicesVar = emitterVisitor.ctx.symbolTable.allocateLocalVariable();
+ emitterVisitor.ctx.mv.visitVarInsn(Opcodes.ASTORE, indicesVar);
+
+ // Load list and indices back, call RuntimeList.getSlice(indices)
+ emitterVisitor.ctx.mv.visitVarInsn(Opcodes.ALOAD, listVar);
+ emitterVisitor.ctx.mv.visitVarInsn(Opcodes.ALOAD, indicesVar);
+ emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
+ "org/perlonjava/runtime/runtimetypes/RuntimeList",
+ "getSlice",
+ "(Lorg/perlonjava/runtime/runtimetypes/RuntimeList;)Lorg/perlonjava/runtime/runtimetypes/RuntimeList;",
+ false);
+
+ // Handle context conversion
+ if (emitterVisitor.ctx.contextType == RuntimeContextType.SCALAR) {
+ emitterVisitor.ctx.mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/perlonjava/runtime/runtimetypes/RuntimeList",
+ "scalar", "()Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;", false);
+ } else if (emitterVisitor.ctx.contextType == RuntimeContextType.VOID) {
+ emitterVisitor.ctx.mv.visitInsn(Opcodes.POP);
+ }
return;
}
+ // For function calls and other expressions: (func())[index]
+ // We need to use list slice semantics to handle empty lists correctly.
+ // However, this should NOT apply to chained dereferences like $matrix[1][0]
+ // where the first [1] returns a scalar (array reference) and the second
+ // [0] should dereference it.
+ //
+ // List slice semantics apply when:
+ // 1. The left side is a ListNode (literal list) - handled above
+ // 2. The left side is a parenthesized function call (wantarray context)
+ //
+ // For now, we use the old transformation to ->[] for non-ListNode cases,
+ // as most cases are array dereferences, not list slices.
+ // TODO: Properly detect when the left side is a list-returning expression
+ // vs. a scalar-returning expression.
+
// default: call `->[]`
BinaryOperatorNode refNode = new BinaryOperatorNode("->", node.left, node.right, node.tokenIndex);
refNode.accept(emitterVisitor);
diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java
index 72180cb0a..90491cf50 100644
--- a/src/main/java/org/perlonjava/core/Configuration.java
+++ b/src/main/java/org/perlonjava/core/Configuration.java
@@ -33,7 +33,7 @@ public final class Configuration {
* Automatically populated by Gradle/Maven during build.
* DO NOT EDIT MANUALLY - this value is replaced at build time.
*/
- public static final String gitCommitId = "38832fe97";
+ public static final String gitCommitId = "427621554";
/**
* Git commit date of the build (ISO format: YYYY-MM-DD).
diff --git a/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java b/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java
index 6df966824..1e0e07a7c 100644
--- a/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java
+++ b/src/main/java/org/perlonjava/frontend/parser/IdentifierParser.java
@@ -201,6 +201,11 @@ public static String parseComplexIdentifierInner(Parser parser, boolean insideBr
if (insideBraces && firstChar == '*' && nextToken.text.equals("{")) {
return null; // Force fallback to expression parsing for glob dereference
}
+ // Special case: & followed by { is subroutine call when inside braces
+ // %{&{$code}} should be parsed as %{ &{$code} }, not %&{$code} (hash subscript on %&)
+ if (insideBraces && firstChar == '&' && nextToken.text.equals("{")) {
+ return null; // Force fallback to expression parsing for subroutine call
+ }
// Check if this is a leading single quote followed by an identifier ($'foo means $main::foo)
if (firstChar == '\'' && (nextToken.type == LexerTokenType.IDENTIFIER || nextToken.type == LexerTokenType.NUMBER)) {
// This is $'foo which means $main::foo
diff --git a/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java b/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java
index 75b0de55c..d63c7dec5 100644
--- a/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java
+++ b/src/main/java/org/perlonjava/runtime/operators/OperatorHandler.java
@@ -310,6 +310,10 @@ public record OperatorHandler(String className, String methodName, int methodTyp
"scalar",
Opcodes.INVOKEVIRTUAL,
"()Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;"));
+
+ // Thread-related (no-op in non-threaded Perl)
+ put("lock", "lock", "org/perlonjava/runtime/operators/TieOperators", "(I[Lorg/perlonjava/runtime/runtimetypes/RuntimeBase;)Lorg/perlonjava/runtime/runtimetypes/RuntimeScalar;");
+
operatorHandlers.put("each",
new OperatorHandler("org/perlonjava/runtime/runtimetypes/RuntimeBase",
"each",
diff --git a/src/main/java/org/perlonjava/runtime/operators/TieOperators.java b/src/main/java/org/perlonjava/runtime/operators/TieOperators.java
index f407bd544..dfcd40ef6 100644
--- a/src/main/java/org/perlonjava/runtime/operators/TieOperators.java
+++ b/src/main/java/org/perlonjava/runtime/operators/TieOperators.java
@@ -215,4 +215,30 @@ public static RuntimeScalar tied(int ctx, RuntimeBase... scalars) {
}
return scalarUndef;
}
+
+ /**
+ * Implements Perl's lock() builtin function.
+ *
+ *
In threaded Perl, lock() places an advisory lock on a shared variable.
+ * In non-threaded Perl (and PerlOnJava), it's a no-op that returns its argument.
+ *
+ * The prototype for lock is \[$@%&*] so the argument is passed as a reference.
+ *
+ * @param ctx the calling context
+ * @param scalars varargs where scalars[0] is a reference to the variable to lock
+ * @return for scalar refs, the dereferenced value; for arrays/hashes, the reference
+ */
+ public static RuntimeScalar lock(int ctx, RuntimeBase... scalars) {
+ // No-op in non-threaded Perl - return the argument appropriately
+ if (scalars.length == 0) {
+ return scalarUndef;
+ }
+ RuntimeScalar variable = scalars[0].getFirst();
+ // For scalar references, dereference to get the value
+ // For other reference types (arrays, hashes), return the reference itself
+ return switch (variable.type) {
+ case REFERENCE -> variable.scalarDeref();
+ default -> variable;
+ };
+ }
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Base.java b/src/main/java/org/perlonjava/runtime/perlmodule/Base.java
index 00f9da3bd..8429bfa55 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Base.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Base.java
@@ -27,6 +27,8 @@ public static void initialize() {
Base base = new Base();
try {
base.registerMethod("import", "importBase", ";$");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("base::VERSION").set(new RuntimeScalar("2.27"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Base method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Parent.java b/src/main/java/org/perlonjava/runtime/perlmodule/Parent.java
index 6e034f82c..a49a76fbb 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Parent.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Parent.java
@@ -29,6 +29,8 @@ public static void initialize() {
Parent parent = new Parent();
try {
parent.registerMethod("import", "importParent", ";$");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("parent::VERSION").set(new RuntimeScalar("0.244"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Parent method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Strict.java b/src/main/java/org/perlonjava/runtime/perlmodule/Strict.java
index 5a4c01a17..ff0325e80 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Strict.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Strict.java
@@ -1,6 +1,7 @@
package org.perlonjava.runtime.perlmodule;
import org.perlonjava.frontend.semantic.ScopedSymbolTable;
+import org.perlonjava.runtime.runtimetypes.GlobalVariable;
import org.perlonjava.runtime.runtimetypes.RuntimeArray;
import org.perlonjava.runtime.runtimetypes.RuntimeList;
import org.perlonjava.runtime.runtimetypes.RuntimeScalar;
@@ -45,6 +46,8 @@ public static void initialize() {
try {
strict.registerMethod("import", "useStrict", ";$");
strict.registerMethod("unimport", "noStrict", ";$");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("strict::VERSION").set(new RuntimeScalar("1.14"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Strict method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java
index 5bc5c63a4..5c7382d22 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java
@@ -47,6 +47,8 @@ public static void initialize() {
utf8.registerMethod("unicode_to_native", "unicodeToNative", "$");
utf8.registerMethod("is_utf8", "isUtf8", "$");
utf8.registerMethod("valid", "$");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("utf8::VERSION").set(new RuntimeScalar("1.29"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Utf8 method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Vars.java b/src/main/java/org/perlonjava/runtime/perlmodule/Vars.java
index 887663951..9fc417268 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Vars.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Vars.java
@@ -19,6 +19,8 @@ public static void initialize() {
Vars vars = new Vars();
try {
vars.registerMethod("import", "importVars", ";$");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("vars::VERSION").set(new RuntimeScalar("1.05"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing vars method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Warnings.java b/src/main/java/org/perlonjava/runtime/perlmodule/Warnings.java
index d8460eccb..ddf7c51ad 100644
--- a/src/main/java/org/perlonjava/runtime/perlmodule/Warnings.java
+++ b/src/main/java/org/perlonjava/runtime/perlmodule/Warnings.java
@@ -33,6 +33,8 @@ public static void initialize() {
warnings.registerMethod("warn", "warn", "$;$");
warnings.registerMethod("warnif", "warnIf", "$;$");
warnings.registerMethod("register_categories", "registerCategories", ";@");
+ // Set $VERSION so CPAN.pm can detect our bundled version
+ GlobalVariable.getGlobalVariable("warnings::VERSION").set(new RuntimeScalar("1.74"));
} catch (NoSuchMethodException e) {
System.err.println("Warning: Missing Warnings method: " + e.getMessage());
}
diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java
index c588fc9fc..38561b9a1 100644
--- a/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java
+++ b/src/main/java/org/perlonjava/runtime/runtimetypes/GlobalVariable.java
@@ -34,6 +34,11 @@ public class GlobalVariable {
static final Map globalIORefs = new HashMap<>();
static final Map globalFormatRefs = new HashMap<>();
+ // Pinned code references: RuntimeScalars that were accessed at compile time
+ // and should survive stash deletion. This matches Perl's behavior where
+ // compiled bytecode holds direct references to CVs that survive stash deletion.
+ private static final Map pinnedCodeRefs = new HashMap<>();
+
// Stash aliasing: `*{Dst::} = *{Src::}` effectively makes Dst:: symbol table
// behave like Src:: for method lookup and stash operations.
// We keep this separate from globalCodeRefs/globalVariables so existing references
@@ -66,6 +71,7 @@ public static void resetAllGlobals() {
globalArrays.clear();
globalHashes.clear();
globalCodeRefs.clear();
+ pinnedCodeRefs.clear();
globalIORefs.clear();
globalFormatRefs.clear();
globalGlobs.clear();
@@ -323,11 +329,23 @@ public static RuntimeHash removeGlobalHash(String key) {
/**
* Retrieves a global code reference by its key, initializing it if necessary.
+ * The returned RuntimeScalar is also pinned, meaning it will survive stash deletion.
+ * This matches Perl's behavior where compiled bytecode holds direct references to CVs.
*
* @param key The key of the global code reference.
* @return The RuntimeScalar representing the global code reference.
*/
public static RuntimeScalar getGlobalCodeRef(String key) {
+ // First check if we have a pinned reference that survives stash deletion
+ RuntimeScalar pinned = pinnedCodeRefs.get(key);
+ if (pinned != null) {
+ // Also ensure it's in globalCodeRefs for normal lookups
+ if (!globalCodeRefs.containsKey(key)) {
+ globalCodeRefs.put(key, pinned);
+ }
+ return pinned;
+ }
+
RuntimeScalar var = globalCodeRefs.get(key);
if (var == null) {
var = new RuntimeScalar();
@@ -351,6 +369,10 @@ public static RuntimeScalar getGlobalCodeRef(String key) {
var.value = runtimeCode;
globalCodeRefs.put(key, var);
}
+
+ // Pin the RuntimeScalar so it survives stash deletion
+ pinnedCodeRefs.put(key, var);
+
return var;
}
diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java
index 65975c2e3..c51b5ec89 100644
--- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java
+++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeGlob.java
@@ -262,9 +262,14 @@ public RuntimeScalar set(RuntimeGlob value) {
// Create ALIASES by making both names point to the same objects in the global maps
// This is the key difference from the old implementation which created references
- // Alias the CODE slot: both names point to the same code reference
+ // Alias the CODE slot: Update the existing RuntimeScalar's value instead of replacing it.
+ // This is critical because compiled code may have cached references to the existing
+ // RuntimeScalar at compile time. Replacing the map entry would leave cached references
+ // pointing to the old (now orphaned) RuntimeScalar, causing calls to fail after
+ // the stash entry is deleted.
RuntimeScalar sourceCode = GlobalVariable.getGlobalCodeRef(globName);
- GlobalVariable.globalCodeRefs.put(this.globName, sourceCode);
+ RuntimeScalar targetCode = GlobalVariable.getGlobalCodeRef(this.globName);
+ targetCode.set(sourceCode); // Copy value into existing RuntimeScalar
// Invalidate the method resolution cache
InheritanceResolver.invalidateCache();
diff --git a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeList.java b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeList.java
index 666868f91..3f89a0f05 100644
--- a/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeList.java
+++ b/src/main/java/org/perlonjava/runtime/runtimetypes/RuntimeList.java
@@ -300,6 +300,43 @@ public RuntimeList each(int ctx) {
throw new PerlCompilerException("Type of arg 1 to each must be hash or array");
}
+ /**
+ * Gets a slice of this list by indices.
+ * This implements proper list slice semantics: if the original list is empty,
+ * the result is an empty list regardless of indices requested.
+ * If the list has elements but an index is out of bounds, undef is returned for that index.
+ *
+ * @param indices The list of indices to extract
+ * @return A RuntimeList containing the elements at the specified indices
+ */
+ public RuntimeList getSlice(RuntimeList indices) {
+ RuntimeList result = new RuntimeList();
+
+ // First, flatten this list to get actual elements
+ RuntimeArray flattened = new RuntimeArray();
+ this.addToArray(flattened);
+ int size = flattened.size();
+
+ // If the source list is empty, return empty list for any indices
+ if (size == 0) {
+ return result;
+ }
+
+ // For each index, get the element (or undef if out of bounds)
+ for (RuntimeScalar indexScalar : indices) {
+ int index = indexScalar.getInt();
+ if (index < 0) {
+ index = size + index;
+ }
+ if (index >= 0 && index < size) {
+ result.elements.add(flattened.get(index));
+ } else {
+ result.elements.add(new RuntimeScalar()); // undef for out of bounds
+ }
+ }
+ return result;
+ }
+
/**
* Removes the last character from each element in the list.
*
diff --git a/src/main/perl/lib/AutoLoader.pm b/src/main/perl/lib/AutoLoader.pm
new file mode 100644
index 000000000..5546f9e99
--- /dev/null
+++ b/src/main/perl/lib/AutoLoader.pm
@@ -0,0 +1,453 @@
+package AutoLoader;
+
+use strict;
+use 5.006_001;
+
+our($VERSION, $AUTOLOAD);
+
+my $is_dosish;
+my $is_epoc;
+my $is_vms;
+my $is_macos;
+
+BEGIN {
+ $is_dosish = $^O eq 'dos' || $^O eq 'os2' || $^O eq 'MSWin32' || $^O eq 'NetWare';
+ $is_epoc = $^O eq 'epoc';
+ $is_vms = $^O eq 'VMS';
+ $is_macos = $^O eq 'MacOS';
+ $VERSION = '5.74';
+}
+
+AUTOLOAD {
+ my $sub = $AUTOLOAD;
+ autoload_sub($sub);
+ goto &$sub;
+}
+
+sub autoload_sub {
+ my $sub = shift;
+
+ my $filename = AutoLoader::find_filename( $sub );
+
+ my $save = $@;
+ local $!; # Do not munge the value.
+ eval { local $SIG{__DIE__}; require $filename };
+ if ($@) {
+ if (substr($sub,-9) eq '::DESTROY') {
+ no strict 'refs';
+ *$sub = sub {};
+ $@ = undef;
+ } elsif ($@ =~ /^Can't locate/) {
+ # The load might just have failed because the filename was too
+ # long for some old SVR3 systems which treat long names as errors.
+ # If we can successfully truncate a long name then it's worth a go.
+ # There is a slight risk that we could pick up the wrong file here
+ # but autosplit should have warned about that when splitting.
+ if ($filename =~ s/(\w{12,})\.al$/substr($1,0,11).".al"/e){
+ eval { local $SIG{__DIE__}; require $filename };
+ }
+ }
+ if ($@){
+ $@ =~ s/ at .*\n//;
+ my $error = $@;
+ require Carp;
+ Carp::croak($error);
+ }
+ }
+ $@ = $save;
+
+ return 1;
+}
+
+sub find_filename {
+ my $sub = shift;
+ my $filename;
+ # Braces used to preserve $1 et al.
+ {
+ # Try to find the autoloaded file from the package-qualified
+ # name of the sub. e.g., if the sub needed is
+ # Getopt::Long::GetOptions(), then $INC{Getopt/Long.pm} is
+ # something like '/usr/lib/perl5/Getopt/Long.pm', and the
+ # autoload file is '/usr/lib/perl5/auto/Getopt/Long/GetOptions.al'.
+ #
+ # However, if @INC is a relative path, this might not work. If,
+ # for example, @INC = ('lib'), then $INC{Getopt/Long.pm} is
+ # 'lib/Getopt/Long.pm', and we want to require
+ # 'auto/Getopt/Long/GetOptions.al' (without the leading 'lib').
+ # In this case, we simple prepend the 'auto/' and let the
+ # C take care of the searching for us.
+
+ my ($pkg,$func) = ($sub =~ /(.*)::([^:]+)$/);
+ $pkg =~ s#::#/#g;
+ if (defined($filename = $INC{"$pkg.pm"})) {
+ if ($is_macos) {
+ $pkg =~ tr#/#:#;
+ $filename = undef
+ unless $filename =~ s#^(.*)$pkg\.pm\z#$1auto:$pkg:$func.al#s;
+ } else {
+ $filename = undef
+ unless $filename =~ s#^(.*)$pkg\.pm\z#$1auto/$pkg/$func.al#s;
+ }
+
+ # if the file exists, then make sure that it is a
+ # a fully anchored path (i.e either '/usr/lib/auto/foo/bar.al',
+ # or './lib/auto/foo/bar.al'. This avoids C searching
+ # (and failing) to find the 'lib/auto/foo/bar.al' because it
+ # looked for 'lib/lib/auto/foo/bar.al', given @INC = ('lib').
+
+ if (defined $filename and -r $filename) {
+ unless ($filename =~ m|^/|s) {
+ if ($is_dosish) {
+ unless ($filename =~ m{^([a-z]:)?[\\/]}is) {
+ if ($^O ne 'NetWare') {
+ $filename = "./$filename";
+ } else {
+ $filename = "$filename";
+ }
+ }
+ }
+ elsif ($is_epoc) {
+ unless ($filename =~ m{^([a-z?]:)?[\\/]}is) {
+ $filename = "./$filename";
+ }
+ }
+ elsif ($is_vms) {
+ # XXX todo by VMSmiths
+ $filename = "./$filename";
+ }
+ elsif (!$is_macos) {
+ $filename = "./$filename";
+ }
+ }
+ }
+ else {
+ $filename = undef;
+ }
+ }
+ unless (defined $filename) {
+ # let C do the searching
+ $filename = "auto/$sub.al";
+ $filename =~ s#::#/#g;
+ }
+ }
+ return $filename;
+}
+
+sub import {
+ my $pkg = shift;
+ my $callpkg = caller;
+
+ #
+ # Export symbols, but not by accident of inheritance.
+ #
+
+ if ($pkg eq 'AutoLoader') {
+ if ( @_ and $_[0] =~ /^&?AUTOLOAD$/ ) {
+ no strict 'refs';
+ *{ $callpkg . '::AUTOLOAD' } = \&AUTOLOAD;
+ }
+ }
+
+ #
+ # Try to find the autosplit index file. Eg., if the call package
+ # is POSIX, then $INC{POSIX.pm} is something like
+ # '/usr/local/lib/perl5/POSIX.pm', and the autosplit index file is in
+ # '/usr/local/lib/perl5/auto/POSIX/autosplit.ix', so we require that.
+ #
+ # However, if @INC is a relative path, this might not work. If,
+ # for example, @INC = ('lib'), then
+ # $INC{POSIX.pm} is 'lib/POSIX.pm', and we want to require
+ # 'auto/POSIX/autosplit.ix' (without the leading 'lib').
+ #
+
+ (my $calldir = $callpkg) =~ s#::#/#g;
+ my $path = $INC{$calldir . '.pm'};
+ if (defined($path)) {
+ # Try absolute path name, but only eval it if the
+ # transformation from module path to autosplit.ix path
+ # succeeded!
+ my $replaced_okay;
+ if ($is_macos) {
+ (my $malldir = $calldir) =~ tr#/#:#;
+ $replaced_okay = ($path =~ s#^(.*)$malldir\.pm\z#$1auto:$malldir:autosplit.ix#s);
+ } else {
+ $replaced_okay = ($path =~ s#^(.*)$calldir\.pm\z#$1auto/$calldir/autosplit.ix#);
+ }
+
+ eval { require $path; } if $replaced_okay;
+ # If that failed, try relative path with normal @INC searching.
+ if (!$replaced_okay or $@) {
+ $path ="auto/$calldir/autosplit.ix";
+ eval { require $path; };
+ }
+ if ($@) {
+ my $error = $@;
+ require Carp;
+ Carp::carp($error);
+ }
+ }
+}
+
+sub unimport {
+ my $callpkg = caller;
+
+ no strict 'refs';
+
+ for my $exported (qw( AUTOLOAD )) {
+ my $symname = $callpkg . '::' . $exported;
+ undef *{ $symname } if \&{ $symname } == \&{ $exported };
+ *{ $symname } = \&{ $symname };
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+AutoLoader - load subroutines only on demand
+
+=head1 SYNOPSIS
+
+ package Foo;
+ use AutoLoader 'AUTOLOAD'; # import the default AUTOLOAD subroutine
+
+ package Bar;
+ use AutoLoader; # don't import AUTOLOAD, define our own
+ sub AUTOLOAD {
+ ...
+ $AutoLoader::AUTOLOAD = "...";
+ goto &AutoLoader::AUTOLOAD;
+ }
+
+=head1 DESCRIPTION
+
+The B module works with the B module and the
+C<__END__> token to defer the loading of some subroutines until they are
+used rather than loading them all at once.
+
+To use B, the author of a module has to place the
+definitions of subroutines to be autoloaded after an C<__END__> token.
+(See L.) The B module can then be run manually to
+extract the definitions into individual files F.
+
+B implements an AUTOLOAD subroutine. When an undefined
+subroutine in is called in a client module of B,
+B's AUTOLOAD subroutine attempts to locate the subroutine in a
+file with a name related to the location of the file from which the
+client module was read. As an example, if F is located in
+F, B will look for perl
+subroutines B in F, where
+the C<.al> file has the same name as the subroutine, sans package. If
+such a file exists, AUTOLOAD will read and evaluate it,
+thus (presumably) defining the needed subroutine. AUTOLOAD will then
+C the newly defined subroutine.
+
+Once this process completes for a given function, it is defined, so
+future calls to the subroutine will bypass the AUTOLOAD mechanism.
+
+=head2 Subroutine Stubs
+
+In order for object method lookup and/or prototype checking to operate
+correctly even when methods have not yet been defined it is necessary to
+"forward declare" each subroutine (as in C). See
+L. Such forward declaration creates "subroutine
+stubs", which are place holders with no code.
+
+The AutoSplit and B modules automate the creation of forward
+declarations. The AutoSplit module creates an 'index' file containing
+forward declarations of all the AutoSplit subroutines. When the
+AutoLoader module is 'use'd it loads these declarations into its callers
+package.
+
+Because of this mechanism it is important that B is always
+Cd and not Cd.
+
+=head2 Using B's AUTOLOAD Subroutine
+
+In order to use B's AUTOLOAD subroutine you I
+explicitly import it:
+
+ use AutoLoader 'AUTOLOAD';
+
+=head2 Overriding B's AUTOLOAD Subroutine
+
+Some modules, mainly extensions, provide their own AUTOLOAD subroutines.
+They typically need to check for some special cases (such as constants)
+and then fallback to B's AUTOLOAD for the rest.
+
+Such modules should I import B's AUTOLOAD subroutine.
+Instead, they should define their own AUTOLOAD subroutines along these
+lines:
+
+ use AutoLoader;
+ use Carp;
+
+ sub AUTOLOAD {
+ my $sub = $AUTOLOAD;
+ (my $constname = $sub) =~ s/.*:://;
+ my $val = constant($constname, @_ ? $_[0] : 0);
+ if ($! != 0) {
+ if ($! =~ /Invalid/ || $!{EINVAL}) {
+ $AutoLoader::AUTOLOAD = $sub;
+ goto &AutoLoader::AUTOLOAD;
+ }
+ else {
+ croak "Your vendor has not defined constant $constname";
+ }
+ }
+ *$sub = sub { $val }; # same as: eval "sub $sub { $val }";
+ goto &$sub;
+ }
+
+If any module's own AUTOLOAD subroutine has no need to fallback to the
+AutoLoader's AUTOLOAD subroutine (because it doesn't have any AutoSplit
+subroutines), then that module should not use B at all.
+
+=head2 Package Lexicals
+
+Package lexicals declared with C in the main block of a package
+using B will not be visible to auto-loaded subroutines, due to
+the fact that the given scope ends at the C<__END__> marker. A module
+using such variables as package globals will not work properly under the
+B.
+
+The C pragma (see L) may be used in such
+situations as an alternative to explicitly qualifying all globals with
+the package namespace. Variables pre-declared with this pragma will be
+visible to any autoloaded routines (but will not be invisible outside
+the package, unfortunately).
+
+=head2 Not Using AutoLoader
+
+You can stop using AutoLoader by simply
+
+ no AutoLoader;
+
+=head2 B vs. B
+
+The B is similar in purpose to B: both delay the
+loading of subroutines.
+
+B uses the C<__DATA__> marker rather than C<__END__>.
+While this avoids the use of a hierarchy of disk files and the
+associated open/close for each routine loaded, B suffers a
+startup speed disadvantage in the one-time parsing of the lines after
+C<__DATA__>, after which routines are cached. B can also
+handle multiple packages in a file.
+
+B only reads code as it is requested, and in many cases
+should be faster, but requires a mechanism like B be used to
+create the individual files. L will invoke
+B automatically if B is used in a module source
+file.
+
+=head2 Forcing AutoLoader to Load a Function
+
+Sometimes, it can be necessary or useful to make sure that a certain
+function is fully loaded by AutoLoader. This is the case, for example,
+when you need to wrap a function to inject debugging code. It is also
+helpful to force early loading of code before forking to make use of
+copy-on-write as much as possible.
+
+Starting with AutoLoader 5.73, you can call the
+C function with the fully-qualified name of
+the function to load from its F<.al> file. The behaviour is exactly
+the same as if you called the function, triggering the regular
+C mechanism, but it does not actually execute the
+autoloaded function.
+
+=head1 CAVEATS
+
+AutoLoaders prior to Perl 5.002 had a slightly different interface. Any
+old modules which use B should be changed to the new calling
+style. Typically this just means changing a require to a use, adding
+the explicit C<'AUTOLOAD'> import if needed, and removing B
+from C<@ISA>.
+
+On systems with restrictions on file name length, the file corresponding
+to a subroutine may have a shorter name that the routine itself. This
+can lead to conflicting file names. The I package warns of
+these potential conflicts when used to split a module.
+
+AutoLoader may fail to find the autosplit files (or even find the wrong
+ones) in cases where C<@INC> contains relative paths, B the program
+does C.
+
+=head1 SEE ALSO
+
+L - an autoloader that doesn't use external files.
+
+=head1 AUTHOR
+
+C is maintained by the perl5-porters. Please direct
+any questions to the canonical mailing list. Anything that
+is applicable to the CPAN release can be sent to its maintainer,
+though.
+
+Author and Maintainer: The Perl5-Porters
+
+Maintainer of the CPAN release: Steffen Mueller
+
+=head1 COPYRIGHT AND LICENSE
+
+This package has been part of the perl core since the first release
+of perl5. It has been released separately to CPAN so older installations
+can benefit from bug fixes.
+
+This package has the same copyright and license as the perl core:
+
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ 2011, 2012, 2013
+ by Larry Wall and others
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ a) the GNU General Public License as published by the Free
+ Software Foundation; either version 1, or (at your option) any
+ later version, or
+
+ b) the "Artistic License" which comes with this Kit.
+
+ 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 either
+ the GNU General Public License or the Artistic License for more details.
+
+ You should have received a copy of the Artistic License with this
+ Kit, in the file named "Artistic". If not, I'll be glad to provide one.
+
+ You should also have received a copy of the GNU General Public License
+ along with this program in the file named "Copying". If not, write to the
+ Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ MA 02110-1301, USA or visit their web page on the internet at
+ http://www.gnu.org/copyleft/gpl.html.
+
+ For those of you that choose to use the GNU General Public License,
+ my interpretation of the GNU General Public License is that no Perl
+ script falls under the terms of the GPL unless you explicitly put
+ said script under the terms of the GPL yourself. Furthermore, any
+ object code linked with perl does not automatically fall under the
+ terms of the GPL, provided such object code only adds definitions
+ of subroutines and variables, and does not otherwise impair the
+ resulting interpreter from executing any standard Perl script. I
+ consider linking in C subroutines in this manner to be the moral
+ equivalent of defining subroutines in the Perl language itself. You
+ may sell such an object file as proprietary provided that you provide
+ or offer to provide the Perl source, as specified by the GNU General
+ Public License. (This is merely an alternate way of specifying input
+ to the program.) You may also sell a binary produced by the dumping of
+ a running Perl script that belongs to you, provided that you provide or
+ offer to provide the Perl source as specified by the GPL. (The
+ fact that a Perl interpreter and your code are in the same binary file
+ is, in this case, a form of mere aggregation.) This is my interpretation
+ of the GPL. If you still have concerns or difficulties understanding
+ my intent, feel free to contact me. Of course, the Artistic License
+ spells all this out for your protection, so you may prefer to use that.
+
+=cut
diff --git a/src/main/perl/lib/AutoSplit.pm b/src/main/perl/lib/AutoSplit.pm
new file mode 100644
index 000000000..c093f2dd2
--- /dev/null
+++ b/src/main/perl/lib/AutoSplit.pm
@@ -0,0 +1,592 @@
+package AutoSplit;
+
+use Exporter ();
+use Config qw(%Config);
+use File::Basename ();
+use File::Path qw(mkpath);
+use File::Spec::Functions qw(curdir catfile catdir);
+use strict;
+our($VERSION, @ISA, @EXPORT, @EXPORT_OK, $Verbose, $Keep, $Maxlen,
+ $CheckForAutoloader, $CheckModTime);
+
+$VERSION = "1.06";
+@ISA = qw(Exporter);
+@EXPORT = qw(&autosplit &autosplit_lib_modules);
+@EXPORT_OK = qw($Verbose $Keep $Maxlen $CheckForAutoloader $CheckModTime);
+
+=head1 NAME
+
+AutoSplit - split a package for autoloading
+
+=head1 SYNOPSIS
+
+ autosplit($file, $dir, $keep, $check, $modtime);
+
+ autosplit_lib_modules(@modules);
+
+=head1 DESCRIPTION
+
+This function will split up your program into files that the AutoLoader
+module can handle. It is used by both the standard perl libraries and by
+the MakeMaker utility, to automatically configure libraries for autoloading.
+
+The C interface splits the specified file into a hierarchy
+rooted at the directory C<$dir>. It creates directories as needed to reflect
+class hierarchy, and creates the file F. This file acts as
+both forward declaration of all package routines, and as timestamp for the
+last update of the hierarchy.
+
+The remaining three arguments to C govern other options to
+the autosplitter.
+
+=over 2
+
+=item $keep
+
+If the third argument, I<$keep>, is false, then any
+pre-existing C<*.al> files in the autoload directory are removed if
+they are no longer part of the module (obsoleted functions).
+$keep defaults to 0.
+
+=item $check
+
+The
+fourth argument, I<$check>, instructs C to check the module
+currently being split to ensure that it includes a C
+specification for the AutoLoader module, and skips the module if
+AutoLoader is not detected.
+$check defaults to 1.
+
+=item $modtime
+
+Lastly, the I<$modtime> argument specifies
+that C is to check the modification time of the module
+against that of the C file, and only split the module if
+it is newer.
+$modtime defaults to 1.
+
+=back
+
+Typical use of AutoSplit in the perl MakeMaker utility is via the command-line
+with:
+
+ perl -e 'use AutoSplit; autosplit($ARGV[0], $ARGV[1], 0, 1, 1)'
+
+Defined as a Make macro, it is invoked with file and directory arguments;
+C will split the specified file into the specified directory and
+delete obsolete C<.al> files, after checking first that the module does use
+the AutoLoader, and ensuring that the module is not already currently split
+in its current form (the modtime test).
+
+The C form is used in the building of perl. It takes
+as input a list of files (modules) that are assumed to reside in a directory
+B relative to the current directory. Each file is sent to the
+autosplitter one at a time, to be split into the directory B.
+
+In both usages of the autosplitter, only subroutines defined following the
+perl I<__END__> token are split out into separate files. Some
+routines may be placed prior to this marker to force their immediate loading
+and parsing.
+
+=head2 Multiple packages
+
+As of version 1.01 of the AutoSplit module it is possible to have
+multiple packages within a single file. Both of the following cases
+are supported:
+
+ package NAME;
+ __END__
+ sub AAA { ... }
+ package NAME::option1;
+ sub BBB { ... }
+ package NAME::option2;
+ sub BBB { ... }
+
+ package NAME;
+ __END__
+ sub AAA { ... }
+ sub NAME::option1::BBB { ... }
+ sub NAME::option2::BBB { ... }
+
+=head1 DIAGNOSTICS
+
+C will inform the user if it is necessary to create the
+top-level directory specified in the invocation. It is preferred that
+the script or installation process that invokes C have
+created the full directory path ahead of time. This warning may
+indicate that the module is being split into an incorrect path.
+
+C will warn the user of all subroutines whose name causes
+potential file naming conflicts on machines with drastically limited
+(8 characters or less) file name length. Since the subroutine name is
+used as the file name, these warnings can aid in portability to such
+systems.
+
+Warnings are issued and the file skipped if C cannot locate
+either the I<__END__> marker or a "package Name;"-style specification.
+
+C will also emit general diagnostics for inability to
+create directories or files.
+
+=head1 AUTHOR
+
+C is maintained by the perl5-porters. Please direct
+any questions to the canonical mailing list. Anything that
+is applicable to the CPAN release can be sent to its maintainer,
+though.
+
+Author and Maintainer: The Perl5-Porters
+
+Maintainer of the CPAN release: Steffen Mueller
+
+=head1 COPYRIGHT AND LICENSE
+
+This package has been part of the perl core since the first release
+of perl5. It has been released separately to CPAN so older installations
+can benefit from bug fixes.
+
+This package has the same copyright and license as the perl core:
+
+ Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ by Larry Wall and others
+
+ All rights reserved.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of either:
+
+ a) the GNU General Public License as published by the Free
+ Software Foundation; either version 1, or (at your option) any
+ later version, or
+
+ b) the "Artistic License" which comes with this Kit.
+
+ 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 either
+ the GNU General Public License or the Artistic License for more details.
+
+ You should have received a copy of the Artistic License with this
+ Kit, in the file named "Artistic". If not, I'll be glad to provide one.
+
+ You should also have received a copy of the GNU General Public License
+ along with this program in the file named "Copying". If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307, USA or visit their web page on the internet at
+ http://www.gnu.org/copyleft/gpl.html.
+
+ For those of you that choose to use the GNU General Public License,
+ my interpretation of the GNU General Public License is that no Perl
+ script falls under the terms of the GPL unless you explicitly put
+ said script under the terms of the GPL yourself. Furthermore, any
+ object code linked with perl does not automatically fall under the
+ terms of the GPL, provided such object code only adds definitions
+ of subroutines and variables, and does not otherwise impair the
+ resulting interpreter from executing any standard Perl script. I
+ consider linking in C subroutines in this manner to be the moral
+ equivalent of defining subroutines in the Perl language itself. You
+ may sell such an object file as proprietary provided that you provide
+ or offer to provide the Perl source, as specified by the GNU General
+ Public License. (This is merely an alternate way of specifying input
+ to the program.) You may also sell a binary produced by the dumping of
+ a running Perl script that belongs to you, provided that you provide or
+ offer to provide the Perl source as specified by the GPL. (The
+ fact that a Perl interpreter and your code are in the same binary file
+ is, in this case, a form of mere aggregation.) This is my interpretation
+ of the GPL. If you still have concerns or difficulties understanding
+ my intent, feel free to contact me. Of course, the Artistic License
+ spells all this out for your protection, so you may prefer to use that.
+
+=cut
+
+# for portability warn about names longer than $maxlen
+$Maxlen = 8; # 8 for dos, 11 (14-".al") for SYSVR3
+$Verbose = 1; # 0=none, 1=minimal, 2=list .al files
+$Keep = 0;
+$CheckForAutoloader = 1;
+$CheckModTime = 1;
+
+my $IndexFile = "autosplit.ix"; # file also serves as timestamp
+my $maxflen = 255;
+$maxflen = 14 if $Config{'d_flexfnam'} ne 'define';
+if (defined (&Dos::UseLFN)) {
+ $maxflen = Dos::UseLFN() ? 255 : 11;
+}
+my $Is_VMS = ($^O eq 'VMS');
+
+# allow checking for valid ': attrlist' attachments.
+# extra jugglery required to support both 5.8 and 5.9/5.10 features
+# (support for 5.8 required for cross-compiling environments)
+
+my $attr_list =
+ $] >= 5.009005 ?
+ eval <<'__QR__'
+ qr{
+ \s* : \s*
+ (?:
+ # one attribute
+ (?> # no backtrack
+ (?! \d) \w+
+ (? \( (?: [^()]++ | (?&nested)++ )*+ \) ) ?
+ )
+ (?: \s* : \s* | \s+ (?! :) )
+ )*
+ }x
+__QR__
+ :
+ do {
+ # In pre-5.9.5 world we have to do dirty tricks.
+ # (we use 'our' rather than 'my' here, due to the rather complex and buggy
+ # behaviour of lexicals with qr// and (??{$lex}) )
+ our $trick1; # yes, cannot our and assign at the same time.
+ $trick1 = qr{ \( (?: (?> [^()]+ ) | (??{ $trick1 }) )* \) }x;
+ our $trick2 = qr{ (?> (?! \d) \w+ (?:$trick1)? ) (?:\s*\:\s*|\s+(?!\:)) }x;
+ qr{ \s* : \s* (?: $trick2 )* }x;
+ };
+
+sub autosplit{
+ my($file, $autodir, $keep, $ckal, $ckmt) = @_;
+ # $file - the perl source file to be split (after __END__)
+ # $autodir - the ".../auto" dir below which to write split subs
+ # Handle optional flags:
+ $keep = $Keep unless defined $keep;
+ $ckal = $CheckForAutoloader unless defined $ckal;
+ $ckmt = $CheckModTime unless defined $ckmt;
+ autosplit_file($file, $autodir, $keep, $ckal, $ckmt);
+}
+
+sub carp{
+ require Carp;
+ goto &Carp::carp;
+}
+
+# This function is used during perl building/installation
+# ./miniperl -e 'use AutoSplit; autosplit_lib_modules(@ARGV)' ...
+
+sub autosplit_lib_modules {
+ my(@modules) = @_; # list of Module names
+ local $_; # Avoid clobber.
+ while (defined($_ = shift @modules)) {
+ while (m#([^:]+)::([^:].*)#) { # in case specified as ABC::XYZ
+ $_ = catfile($1, $2);
+ }
+ s|\\|/|g; # bug in ksh OS/2
+ s#^lib/##s; # incase specified as lib/*.pm
+ my($lib) = catfile(curdir(), "lib");
+ if ($Is_VMS) { # may need to convert VMS-style filespecs
+ $lib =~ s#^\[\]#.\/#;
+ }
+ s#^$lib\W+##s; # incase specified as ./lib/*.pm
+ if ($Is_VMS && /[:>\]]/) { # may need to convert VMS-style filespecs
+ my ($dir,$name) = (/(.*])(.*)/s);
+ $dir =~ s/.*lib[\.\]]//s;
+ $dir =~ s#[\.\]]#/#g;
+ $_ = $dir . $name;
+ }
+ autosplit_file(catfile($lib, $_), catfile($lib, "auto"),
+ $Keep, $CheckForAutoloader, $CheckModTime);
+ }
+ 0;
+}
+
+
+# private functions
+
+my $self_mod_time = (stat __FILE__)[9];
+
+sub autosplit_file {
+ my($filename, $autodir, $keep, $check_for_autoloader, $check_mod_time)
+ = @_;
+ my(@outfiles);
+ local($_);
+ local($/) = "\n";
+
+ # where to write output files
+ $autodir ||= catfile(curdir(), "lib", "auto");
+ if ($Is_VMS) {
+ ($autodir = VMS::Filespec::unixpath($autodir)) =~ s|/\z||;
+ $filename = VMS::Filespec::unixify($filename); # may have dirs
+ }
+ unless (-d $autodir){
+ mkpath($autodir,0,0755);
+ # We should never need to create the auto dir
+ # here. installperl (or similar) should have done
+ # it. Expecting it to exist is a valuable sanity check against
+ # autosplitting into some random directory by mistake.
+ print "Warning: AutoSplit had to create top-level " .
+ "$autodir unexpectedly.\n";
+ }
+
+ # allow just a package name to be used
+ $filename .= ".pm" unless ($filename =~ m/\.pm\z/);
+
+ open(my $in, "<$filename") or die "AutoSplit: Can't open $filename: $!\n";
+ my($pm_mod_time) = (stat($filename))[9];
+ my($autoloader_seen) = 0;
+ my($in_pod) = 0;
+ my($def_package,$last_package,$this_package,$fnr);
+ while (<$in>) {
+ # Skip pod text.
+ $fnr++;
+ $in_pod = 1 if /^=\w/;
+ $in_pod = 0 if /^=cut/;
+ next if ($in_pod || /^=cut/);
+ next if /^\s*#/;
+
+ # record last package name seen
+ $def_package = $1 if (m/^\s*package\s+([\w:]+)\s*;/);
+ ++$autoloader_seen if m/^\s*(use|require)\s+AutoLoader\b/;
+ ++$autoloader_seen if m/\bISA\s*=.*\bAutoLoader\b/;
+ last if /^__END__/;
+ }
+ if ($check_for_autoloader && !$autoloader_seen){
+ print "AutoSplit skipped $filename: no AutoLoader used\n"
+ if ($Verbose>=2);
+ return 0;
+ }
+ $_ or die "Can't find __END__ in $filename\n";
+
+ $def_package or die "Can't find 'package Name;' in $filename\n";
+
+ my($modpname) = _modpname($def_package);
+
+ # this _has_ to match so we have a reasonable timestamp file
+ die "Package $def_package ($modpname.pm) does not ".
+ "match filename $filename"
+ unless ($filename =~ m/\Q$modpname.pm\E$/ or
+ ($^O eq 'dos') or ($^O eq 'MSWin32') or ($^O eq 'NetWare') or
+ $Is_VMS && $filename =~ m/$modpname.pm/i);
+
+ my($al_idx_file) = catfile($autodir, $modpname, $IndexFile);
+
+ if ($check_mod_time){
+ my($al_ts_time) = (stat("$al_idx_file"))[9] || 1;
+ if ($al_ts_time >= $pm_mod_time and
+ $al_ts_time >= $self_mod_time){
+ print "AutoSplit skipped ($al_idx_file newer than $filename)\n"
+ if ($Verbose >= 2);
+ return undef; # one undef, not a list
+ }
+ }
+
+ my($modnamedir) = catdir($autodir, $modpname);
+ print "AutoSplitting $filename ($modnamedir)\n"
+ if $Verbose;
+
+ unless (-d $modnamedir){
+ mkpath($modnamedir,0,0777);
+ }
+
+ # We must try to deal with some SVR3 systems with a limit of 14
+ # characters for file names. Sadly we *cannot* simply truncate all
+ # file names to 14 characters on these systems because we *must*
+ # create filenames which exactly match the names used by AutoLoader.pm.
+ # This is a problem because some systems silently truncate the file
+ # names while others treat long file names as an error.
+
+ my $Is83 = $maxflen==11; # plain, case INSENSITIVE dos filenames
+
+ my(@subnames, $subname, %proto, %package);
+ my @cache = ();
+ my $caching = 1;
+ $last_package = '';
+ my $out;
+ while (<$in>) {
+ $fnr++;
+ $in_pod = 1 if /^=\w/;
+ $in_pod = 0 if /^=cut/;
+ next if ($in_pod || /^=cut/);
+ # the following (tempting) old coding gives big troubles if a
+ # cut is forgotten at EOF:
+ # next if /^=\w/ .. /^=cut/;
+ if (/^package\s+([\w:]+)\s*;/) {
+ $this_package = $def_package = $1;
+ }
+
+ if (/^sub\s+([\w:]+)(\s*(?:\(.*?\))?(?:$attr_list)?)/) {
+ print $out "# end of $last_package\::$subname\n1;\n"
+ if $last_package;
+ $subname = $1;
+ my $proto = $2 || '';
+ if ($subname =~ s/(.*):://){
+ $this_package = $1;
+ } else {
+ $this_package = $def_package;
+ }
+ my $fq_subname = "$this_package\::$subname";
+ $package{$fq_subname} = $this_package;
+ $proto{$fq_subname} = $proto;
+ push(@subnames, $fq_subname);
+ my($lname, $sname) = ($subname, substr($subname,0,$maxflen-3));
+ $modpname = _modpname($this_package);
+ my($modnamedir) = catdir($autodir, $modpname);
+ mkpath($modnamedir,0,0777);
+ my($lpath) = catfile($modnamedir, "$lname.al");
+ my($spath) = catfile($modnamedir, "$sname.al");
+ my $path;
+
+ if (!$Is83 and open($out, ">$lpath")){
+ $path=$lpath;
+ print " writing $lpath\n" if ($Verbose>=2);
+ } else {
+ open($out, ">$spath") or die "Can't create $spath: $!\n";
+ $path=$spath;
+ print " writing $spath (with truncated name)\n"
+ if ($Verbose>=1);
+ }
+ push(@outfiles, $path);
+ my $lineno = $fnr - @cache;
+ print $out < lc($_) } @outfiles;
+ } else {
+ @outfiles{@outfiles} = @outfiles;
+ }
+ my(%outdirs,@outdirs);
+ for (@outfiles) {
+ $outdirs{File::Basename::dirname($_)}||=1;
+ }
+ for my $dir (keys %outdirs) {
+ opendir(my $outdir,$dir);
+ foreach (sort readdir($outdir)){
+ next unless /\.al\z/;
+ my($file) = catfile($dir, $_);
+ $file = lc $file if $Is83 or $Is_VMS;
+ next if $outfiles{$file};
+ print " deleting $file\n" if ($Verbose>=2);
+ my($deleted,$thistime); # catch all versions on VMS
+ do { $deleted += ($thistime = unlink $file) } while ($thistime);
+ carp ("Unable to delete $file: $!") unless $deleted;
+ }
+ closedir($outdir);
+ }
+ }
+
+ open(my $ts,">$al_idx_file") or
+ carp ("AutoSplit: unable to create timestamp file ($al_idx_file): $!");
+ print $ts "# Index created by AutoSplit for $filename\n";
+ print $ts "# (file acts as timestamp)\n";
+ $last_package = '';
+ for my $fqs (@subnames) {
+ my($subname) = $fqs;
+ $subname =~ s/.*:://;
+ print $ts "package $package{$fqs};\n"
+ unless $last_package eq $package{$fqs};
+ print $ts "sub $subname $proto{$fqs};\n";
+ $last_package = $package{$fqs};
+ }
+ print $ts "1;\n";
+ close($ts);
+
+ _check_unique($filename, $Maxlen, 1, @outfiles);
+
+ @outfiles;
+}
+
+sub _modpname ($) {
+ my($package) = @_;
+ my $modpname = $package;
+ if ($^O eq 'MSWin32') {
+ $modpname =~ s#::#\\#g;
+ } else {
+ my @modpnames = ();
+ while ($modpname =~ m#(.*?[^:])::([^:].*)#) {
+ push @modpnames, $1;
+ $modpname = $2;
+ }
+ $modpname = catfile(@modpnames, $modpname);
+ }
+ if ($Is_VMS) {
+ $modpname = VMS::Filespec::unixify($modpname); # may have dirs
+ }
+ $modpname;
+}
+
+sub _check_unique {
+ my($filename, $maxlen, $warn, @outfiles) = @_;
+ my(%notuniq) = ();
+ my(%shorts) = ();
+ my(@toolong) = grep(
+ length(File::Basename::basename($_))
+ > $maxlen,
+ @outfiles
+ );
+
+ foreach (@toolong){
+ my($dir) = File::Basename::dirname($_);
+ my($file) = File::Basename::basename($_);
+ my($trunc) = substr($file,0,$maxlen);
+ $notuniq{$dir}{$trunc} = 1 if $shorts{$dir}{$trunc};
+ $shorts{$dir}{$trunc} = $shorts{$dir}{$trunc} ?
+ "$shorts{$dir}{$trunc}, $file" : $file;
+ }
+ if (%notuniq && $warn){
+ print "$filename: some names are not unique when " .
+ "truncated to $maxlen characters:\n";
+ foreach my $dir (sort keys %notuniq){
+ print " directory $dir:\n";
+ foreach my $trunc (sort keys %{$notuniq{$dir}}) {
+ print " $shorts{$dir}{$trunc} truncate to $trunc\n";
+ }
+ }
+ }
+}
+
+1;
+__END__
+
+# test functions so AutoSplit.pm can be applied to itself:
+sub test1 ($) { "test 1\n"; }
+sub test2 ($$) { "test 2\n"; }
+sub test3 ($$$) { "test 3\n"; }
+sub testtesttesttest4_1 { "test 4\n"; }
+sub testtesttesttest4_2 { "duplicate test 4\n"; }
+sub Just::Another::test5 { "another test 5\n"; }
+sub test6 { return join ":", __FILE__,__LINE__; }
+package Yet::Another::AutoSplit;
+sub testtesttesttest4_1 ($) { "another test 4\n"; }
+sub testtesttesttest4_2 ($$) { "another duplicate test 4\n"; }
+package Yet::More::Attributes;
+sub test_a1 ($) : locked :locked { 1; }
+sub test_a2 : locked { 1; }
diff --git a/src/main/perl/lib/B.pm b/src/main/perl/lib/B.pm
index 045af3d1b..6e0233cff 100644
--- a/src/main/perl/lib/B.pm
+++ b/src/main/perl/lib/B.pm
@@ -20,7 +20,7 @@ our $VERSION = '1.00_perlonjava';
# Export functionality
use Exporter 'import';
-our @EXPORT_OK = qw(svref_2object perlstring CVf_ANON SVf_IOK);
+our @EXPORT_OK = qw(svref_2object perlstring CVf_ANON SVf_IOK SVf_POK);
our %EXPORT_TAGS = (
all => \@EXPORT_OK,
);
@@ -31,6 +31,7 @@ our $INCOMPLETE = 1;
# SV flags (very partial)
use constant {
SVf_IOK => 0x0001,
+ SVf_POK => 0x0002,
};
# CV flags
@@ -54,9 +55,16 @@ package B::SV {
# For the debugger source arrays (@{"_<..."}), perl stores lines as PVIV with IOK.
# This stub implementation marks any defined, non-empty scalar as having IOK.
+ # Also mark strings with SVf_POK for CPAN::Meta::YAML compatibility.
if (ref($r) eq 'SCALAR') {
my $v = $$r;
- return (defined($v) && length($v)) ? B::SVf_IOK() : 0;
+ my $flags = 0;
+ if (defined($v) && length($v)) {
+ $flags |= B::SVf_IOK();
+ # If the value is a string (not purely numeric), set POK
+ $flags |= B::SVf_POK() unless Scalar::Util::looks_like_number($v);
+ }
+ return $flags;
}
return 0;
@@ -182,6 +190,9 @@ sub CVf_ANON() { return 0x0004; }
# Export SVf_IOK as a function
sub SVf_IOK() { return 0x0001; }
+# Export SVf_POK as a function
+sub SVf_POK() { return 0x0002; }
+
# Convert a string to its Perl source representation
# This is used by modules like Specio for code generation
sub perlstring {
diff --git a/src/main/perl/lib/Encode.pm b/src/main/perl/lib/Encode.pm
new file mode 100644
index 000000000..491604a8f
--- /dev/null
+++ b/src/main/perl/lib/Encode.pm
@@ -0,0 +1,20 @@
+package Encode;
+use strict;
+use warnings;
+our $VERSION = '3.21';
+
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(decode encode encode_utf8 decode_utf8 find_encoding);
+our @EXPORT_OK = qw(
+ _utf8_off _utf8_on define_encoding from_to is_utf8
+ perlio_ok resolve_alias
+ encodings
+ FB_DEFAULT FB_CROAK FB_QUIET FB_WARN FB_HTMLCREF FB_XMLCREF
+ LEAVE_SRC
+);
+
+use XSLoader;
+XSLoader::load('Encode', $VERSION);
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/Command.pm b/src/main/perl/lib/ExtUtils/Command.pm
new file mode 100644
index 000000000..5dd1bd207
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Command.pm
@@ -0,0 +1,381 @@
+package ExtUtils::Command;
+
+use 5.00503;
+use strict;
+use warnings;
+require Exporter;
+our @ISA = qw(Exporter);
+our @EXPORT = qw(cp rm_f rm_rf mv cat eqtime mkpath touch test_f test_d chmod
+ dos2unix);
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+my $Is_VMS = $^O eq 'VMS';
+my $Is_VMS_mode = $Is_VMS;
+my $Is_VMS_noefs = $Is_VMS;
+my $Is_Win32 = $^O eq 'MSWin32';
+
+if( $Is_VMS ) {
+ my $vms_unix_rpt;
+ my $vms_efs;
+ my $vms_case;
+
+ if (eval { local $SIG{__DIE__};
+ local @INC = @INC;
+ pop @INC if $INC[-1] eq '.';
+ require VMS::Feature; }) {
+ $vms_unix_rpt = VMS::Feature::current("filename_unix_report");
+ $vms_efs = VMS::Feature::current("efs_charset");
+ $vms_case = VMS::Feature::current("efs_case_preserve");
+ } else {
+ my $unix_rpt = $ENV{'DECC$FILENAME_UNIX_REPORT'} || '';
+ my $efs_charset = $ENV{'DECC$EFS_CHARSET'} || '';
+ my $efs_case = $ENV{'DECC$EFS_CASE_PRESERVE'} || '';
+ $vms_unix_rpt = $unix_rpt =~ /^[ET1]/i;
+ $vms_efs = $efs_charset =~ /^[ET1]/i;
+ $vms_case = $efs_case =~ /^[ET1]/i;
+ }
+ $Is_VMS_mode = 0 if $vms_unix_rpt;
+ $Is_VMS_noefs = 0 if ($vms_efs);
+}
+
+
+=head1 NAME
+
+ExtUtils::Command - utilities to replace common UNIX commands in Makefiles etc.
+
+=head1 SYNOPSIS
+
+ perl -MExtUtils::Command -e cat files... > destination
+ perl -MExtUtils::Command -e mv source... destination
+ perl -MExtUtils::Command -e cp source... destination
+ perl -MExtUtils::Command -e touch files...
+ perl -MExtUtils::Command -e rm_f files...
+ perl -MExtUtils::Command -e rm_rf directories...
+ perl -MExtUtils::Command -e mkpath directories...
+ perl -MExtUtils::Command -e eqtime source destination
+ perl -MExtUtils::Command -e test_f file
+ perl -MExtUtils::Command -e test_d directory
+ perl -MExtUtils::Command -e chmod mode files...
+ ...
+
+=head1 DESCRIPTION
+
+The module is used to replace common UNIX commands. In all cases the
+functions work from @ARGV rather than taking arguments. This makes
+them easier to deal with in Makefiles. Call them like this:
+
+ perl -MExtUtils::Command -e some_command some files to work on
+
+and I like this:
+
+ perl -MExtUtils::Command -e 'some_command qw(some files to work on)'
+
+For that use L.
+
+Filenames with * and ? will be glob expanded.
+
+
+=head2 FUNCTIONS
+
+=over 4
+
+=cut
+
+# VMS uses % instead of ? to mean "one character"
+my $wild_regex = $Is_VMS ? '*%' : '*?';
+sub expand_wildcards
+{
+ @ARGV = map(/[$wild_regex]/o ? glob($_) : $_,@ARGV);
+}
+
+
+=item cat
+
+ cat file ...
+
+Concatenates all files mentioned on command line to STDOUT.
+
+=cut
+
+sub cat ()
+{
+ expand_wildcards();
+ print while (<>);
+}
+
+=item eqtime
+
+ eqtime source destination
+
+Sets modified time of destination to that of source.
+
+=cut
+
+sub eqtime
+{
+ my ($src,$dst) = @ARGV;
+ local @ARGV = ($dst); touch(); # in case $dst doesn't exist
+ utime((stat($src))[8,9],$dst);
+}
+
+=item rm_rf
+
+ rm_rf files or directories ...
+
+Removes files and directories - recursively (even if readonly)
+
+=cut
+
+sub rm_rf
+{
+ expand_wildcards();
+ require File::Path;
+ File::Path::rmtree([grep -e $_,@ARGV],0,0);
+}
+
+=item rm_f
+
+ rm_f file ...
+
+Removes files (even if readonly)
+
+=cut
+
+sub rm_f {
+ expand_wildcards();
+
+ foreach my $file (@ARGV) {
+ next unless -f $file;
+
+ next if _unlink($file);
+
+ chmod(0777, $file);
+
+ next if _unlink($file);
+
+ require Carp;
+ Carp::carp("Cannot delete $file: $!");
+ }
+}
+
+sub _unlink {
+ my $files_unlinked = 0;
+ foreach my $file (@_) {
+ my $delete_count = 0;
+ $delete_count++ while unlink $file;
+ $files_unlinked++ if $delete_count;
+ }
+ return $files_unlinked;
+}
+
+
+=item touch
+
+ touch file ...
+
+Makes files exist, with current timestamp
+
+=cut
+
+sub touch {
+ my $t = time;
+ expand_wildcards();
+ foreach my $file (@ARGV) {
+ open(FILE,">>$file") || die "Cannot write $file:$!";
+ close(FILE);
+ utime($t,$t,$file);
+ }
+}
+
+=item mv
+
+ mv source_file destination_file
+ mv source_file source_file destination_dir
+
+Moves source to destination. Multiple sources are allowed if
+destination is an existing directory.
+
+Returns true if all moves succeeded, false otherwise.
+
+=cut
+
+sub mv {
+ expand_wildcards();
+ my @src = @ARGV;
+ my $dst = pop @src;
+
+ if (@src > 1 && ! -d $dst) {
+ require Carp;
+ Carp::croak("Too many arguments");
+ }
+
+ require File::Copy;
+ my $nok = 0;
+ foreach my $src (@src) {
+ $nok ||= !File::Copy::move($src,$dst);
+ }
+ return !$nok;
+}
+
+=item cp
+
+ cp source_file destination_file
+ cp source_file source_file destination_dir
+
+Copies sources to the destination. Multiple sources are allowed if
+destination is an existing directory.
+
+Returns true if all copies succeeded, false otherwise.
+
+=cut
+
+sub cp {
+ expand_wildcards();
+ my @src = @ARGV;
+ my $dst = pop @src;
+
+ if (@src > 1 && ! -d $dst) {
+ require Carp;
+ Carp::croak("Too many arguments");
+ }
+
+ require File::Copy;
+ my $nok = 0;
+ foreach my $src (@src) {
+ $nok ||= !File::Copy::copy($src,$dst);
+
+ # Win32 does not update the mod time of a copied file, just the
+ # created time which make does not look at.
+ utime(time, time, $dst) if $Is_Win32;
+ }
+ return $nok;
+}
+
+=item chmod
+
+ chmod mode files ...
+
+Sets UNIX like permissions 'mode' on all the files. e.g. 0666
+
+=cut
+
+sub chmod {
+ local @ARGV = @ARGV;
+ my $mode = shift(@ARGV);
+ expand_wildcards();
+
+ if( $Is_VMS_mode && $Is_VMS_noefs) {
+ require File::Spec;
+ foreach my $idx (0..$#ARGV) {
+ my $path = $ARGV[$idx];
+ next unless -d $path;
+
+ # chmod 0777, [.foo.bar] doesn't work on VMS, you have to do
+ # chmod 0777, [.foo]bar.dir
+ my @dirs = File::Spec->splitdir( $path );
+ $dirs[-1] .= '.dir';
+ $path = File::Spec->catfile(@dirs);
+
+ $ARGV[$idx] = $path;
+ }
+ }
+
+ chmod(oct $mode,@ARGV) || die "Cannot chmod ".join(' ',$mode,@ARGV).":$!";
+}
+
+=item mkpath
+
+ mkpath directory ...
+
+Creates directories, including any parent directories.
+
+=cut
+
+sub mkpath
+{
+ expand_wildcards();
+ require File::Path;
+ File::Path::mkpath([@ARGV],0,0777);
+}
+
+=item test_f
+
+ test_f file
+
+Tests if a file exists. I with 0 if it does, 1 if it does not (ie.
+shell's idea of true and false).
+
+=cut
+
+sub test_f
+{
+ exit(-f $ARGV[0] ? 0 : 1);
+}
+
+=item test_d
+
+ test_d directory
+
+Tests if a directory exists. I with 0 if it does, 1 if it does
+not (ie. shell's idea of true and false).
+
+=cut
+
+sub test_d
+{
+ exit(-d $ARGV[0] ? 0 : 1);
+}
+
+=item dos2unix
+
+ dos2unix files or dirs ...
+
+Converts DOS and OS/2 linefeeds to Unix style recursively.
+
+=cut
+
+sub dos2unix {
+ require File::Find;
+ File::Find::find(sub {
+ return if -d;
+ return unless -w _;
+ return unless -r _;
+ return if -B _;
+
+ local $\;
+
+ my $orig = $_;
+ my $temp = '.dos2unix_tmp';
+ open ORIG, $_ or do { warn "dos2unix can't open $_: $!"; return };
+ open TEMP, ">$temp" or
+ do { warn "dos2unix can't create .dos2unix_tmp: $!"; return };
+ binmode ORIG; binmode TEMP;
+ while (my $line = ) {
+ $line =~ s/\015\012/\012/g;
+ print TEMP $line;
+ }
+ close ORIG;
+ close TEMP;
+ rename $temp, $orig;
+
+ }, @ARGV);
+}
+
+=back
+
+=head1 SEE ALSO
+
+Shell::Command which is these same functions but take arguments normally.
+
+
+=head1 AUTHOR
+
+Nick Ing-Simmons C
+
+Maintained by Michael G Schwern C within the
+ExtUtils-MakeMaker package and, as a separate CPAN package, by
+Randy Kobes C.
+
+=cut
+
diff --git a/src/main/perl/lib/ExtUtils/Command/MM.pm b/src/main/perl/lib/ExtUtils/Command/MM.pm
new file mode 100644
index 000000000..642d5aafb
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Command/MM.pm
@@ -0,0 +1,323 @@
+package ExtUtils::Command::MM;
+
+require 5.006;
+
+use strict;
+use warnings;
+
+require Exporter;
+our @ISA = qw(Exporter);
+
+our @EXPORT = qw(test_harness pod2man perllocal_install uninstall
+ warn_if_old_packlist test_s cp_nonempty);
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+my $Is_VMS = $^O eq 'VMS';
+
+sub mtime {
+ no warnings 'redefine';
+ local $@;
+ *mtime = (eval { require Time::HiRes } && defined &Time::HiRes::stat)
+ ? sub { (Time::HiRes::stat($_[0]))[9] }
+ : sub { ( stat($_[0]))[9] }
+ ;
+ goto &mtime;
+}
+
+=head1 NAME
+
+ExtUtils::Command::MM - Commands for the MM's to use in Makefiles
+
+=head1 SYNOPSIS
+
+ perl "-MExtUtils::Command::MM" -e "function" "--" arguments...
+
+
+=head1 DESCRIPTION
+
+B The interface is not stable.
+
+ExtUtils::Command::MM encapsulates code which would otherwise have to
+be done with large "one" liners.
+
+Any $(FOO) used in the examples are make variables, not Perl.
+
+=over 4
+
+=item B
+
+ test_harness($verbose, @test_libs);
+
+Runs the tests on @ARGV via Test::Harness passing through the $verbose
+flag. Any @test_libs will be unshifted onto the test's @INC.
+
+@test_libs are run in alphabetical order.
+
+=cut
+
+sub test_harness {
+ require Test::Harness;
+ require File::Spec;
+
+ $Test::Harness::verbose = shift;
+
+ # Because Windows doesn't do this for us and listing all the *.t files
+ # out on the command line can blow over its exec limit.
+ require ExtUtils::Command;
+ my @argv = ExtUtils::Command::expand_wildcards(@ARGV);
+
+ local @INC = @INC;
+ unshift @INC, map { File::Spec->rel2abs($_) } @_;
+ Test::Harness::runtests(sort { lc $a cmp lc $b } @argv);
+}
+
+
+
+=item B
+
+ pod2man( '--option=value',
+ $podfile1 => $manpage1,
+ $podfile2 => $manpage2,
+ ...
+ );
+
+ # or args on @ARGV
+
+pod2man() is a function performing most of the duties of the pod2man
+program. Its arguments are exactly the same as pod2man as of 5.8.0
+with the addition of:
+
+ --perm_rw octal permission to set the resulting manpage to
+
+And the removal of:
+
+ --verbose/-v
+ --help/-h
+
+If no arguments are given to pod2man it will read from @ARGV.
+
+If Pod::Man is unavailable, this function will warn and return undef.
+
+=cut
+
+sub pod2man {
+ local @ARGV = @_ ? @_ : @ARGV;
+
+ {
+ local $@;
+ if( !eval { require Pod::Man } ) {
+ warn "Pod::Man is not available: $@".
+ "Man pages will not be generated during this install.\n";
+ return 0;
+ }
+ }
+ require Getopt::Long;
+
+ # We will cheat and just use Getopt::Long. We fool it by putting
+ # our arguments into @ARGV. Should be safe.
+ my %options = ();
+ Getopt::Long::config ('bundling_override');
+ Getopt::Long::GetOptions (\%options,
+ 'section|s=s', 'release|r=s', 'center|c=s',
+ 'date|d=s', 'fixed=s', 'fixedbold=s', 'fixeditalic=s',
+ 'fixedbolditalic=s', 'official|o', 'quotes|q=s', 'lax|l',
+ 'name|n=s', 'perm_rw=i', 'utf8|u'
+ );
+ delete $options{utf8} unless $Pod::Man::VERSION >= 2.17;
+
+ # If there's no files, don't bother going further.
+ return 0 unless @ARGV;
+
+ # Official sets --center, but don't override things explicitly set.
+ if ($options{official} && !defined $options{center}) {
+ $options{center} = q[Perl Programmer's Reference Guide];
+ }
+
+ # This isn't a valid Pod::Man option and is only accepted for backwards
+ # compatibility.
+ delete $options{lax};
+ my $count = scalar @ARGV / 2;
+ my $plural = $count == 1 ? 'document' : 'documents';
+ print "Manifying $count pod $plural\n";
+
+ do {{ # so 'next' works
+ my ($pod, $man) = splice(@ARGV, 0, 2);
+
+ next if ((-e $man) &&
+ (mtime($man) > mtime($pod)) &&
+ (mtime($man) > mtime("Makefile")));
+
+ my $parser = Pod::Man->new(%options);
+ $parser->parse_from_file($pod, $man)
+ or do { warn("Could not install $man\n"); next };
+
+ if (exists $options{perm_rw}) {
+ chmod(oct($options{perm_rw}), $man)
+ or do { warn("chmod $options{perm_rw} $man: $!\n"); next };
+ }
+ }} while @ARGV;
+
+ return 1;
+}
+
+
+=item B
+
+ perl "-MExtUtils::Command::MM" -e warn_if_old_packlist
+
+Displays a warning that an old packlist file was found. Reads the
+filename from @ARGV.
+
+=cut
+
+sub warn_if_old_packlist {
+ my $packlist = $ARGV[0];
+
+ return unless -f $packlist;
+ print <<"PACKLIST_WARNING";
+WARNING: I have found an old package in
+ $packlist.
+Please make sure the two installations are not conflicting
+PACKLIST_WARNING
+
+}
+
+
+=item B
+
+ perl "-MExtUtils::Command::MM" -e perllocal_install
+ ...
+
+ # VMS only, key|value pairs come on STDIN
+ perl "-MExtUtils::Command::MM" -e perllocal_install
+ < | ...
+
+Prints a fragment of POD suitable for appending to perllocal.pod.
+Arguments are read from @ARGV.
+
+'type' is the type of what you're installing. Usually 'Module'.
+
+'module name' is simply the name of your module. (Foo::Bar)
+
+Key/value pairs are extra information about the module. Fields include:
+
+ installed into which directory your module was out into
+ LINKTYPE dynamic or static linking
+ VERSION module version number
+ EXE_FILES any executables installed in a space separated
+ list
+
+=cut
+
+sub perllocal_install {
+ my($type, $name) = splice(@ARGV, 0, 2);
+
+ # VMS feeds args as a piped file on STDIN since it usually can't
+ # fit all the args on a single command line.
+ my @mod_info = $Is_VMS ? split /\|/,
+ : @ARGV;
+
+ my $pod;
+ my $time = gmtime($ENV{SOURCE_DATE_EPOCH} || time);
+ $pod = sprintf <<'POD', scalar($time), $type, $name, $name;
+ =head2 %s: C<%s> L<%s|%s>
+
+ =over 4
+
+POD
+
+ do {
+ my($key, $val) = splice(@mod_info, 0, 2);
+
+ $pod .= <
+
+POD
+
+ } while(@mod_info);
+
+ $pod .= "=back\n\n";
+ $pod =~ s/^ //mg;
+ print $pod;
+
+ return 1;
+}
+
+=item B
+
+ perl "-MExtUtils::Command::MM" -e uninstall
+
+A wrapper around ExtUtils::Install::uninstall(). Warns that
+uninstallation is deprecated and doesn't actually perform the
+uninstallation.
+
+=cut
+
+sub uninstall {
+ my($packlist) = shift @ARGV;
+
+ require ExtUtils::Install;
+
+ print <<'WARNING';
+
+Uninstall is unsafe and deprecated, the uninstallation was not performed.
+We will show what would have been done.
+
+WARNING
+
+ ExtUtils::Install::uninstall($packlist, 1, 1);
+
+ print <<'WARNING';
+
+Uninstall is unsafe and deprecated, the uninstallation was not performed.
+Please check the list above carefully, there may be errors.
+Remove the appropriate files manually.
+Sorry for the inconvenience.
+
+WARNING
+
+}
+
+=item B
+
+ perl "-MExtUtils::Command::MM" -e test_s
+
+Tests if a file exists and is not empty (size > 0).
+I with 0 if it does, 1 if it does not.
+
+=cut
+
+sub test_s {
+ exit(-s $ARGV[0] ? 0 : 1);
+}
+
+=item B
+
+ perl "-MExtUtils::Command::MM" -e cp_nonempty
+
+Tests if the source file exists and is not empty (size > 0). If it is not empty
+it copies it to the given destination with the given permissions.
+
+=back
+
+=cut
+
+sub cp_nonempty {
+ my @args = @ARGV;
+ return 0 unless -s $args[0];
+ require ExtUtils::Command;
+ {
+ local @ARGV = @args[0,1];
+ ExtUtils::Command::cp(@ARGV);
+ }
+ {
+ local @ARGV = @args[2,1];
+ ExtUtils::Command::chmod(@ARGV);
+ }
+}
+
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/Install.pm b/src/main/perl/lib/ExtUtils/Install.pm
new file mode 100644
index 000000000..83db80df5
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Install.pm
@@ -0,0 +1,1335 @@
+package ExtUtils::Install;
+use strict;
+
+use Config qw(%Config);
+use Cwd qw(cwd);
+use Exporter ();
+use File::Basename qw(dirname);
+use File::Copy;
+use File::Path;
+use File::Spec;
+
+our @ISA = ('Exporter');
+our @EXPORT = ('install','uninstall','pm_to_blib', 'install_default');
+
+our $MUST_REBOOT;
+
+=pod
+
+=head1 NAME
+
+ExtUtils::Install - install files from here to there
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Install;
+
+ install({ 'blib/lib' => 'some/install/dir' } );
+
+ uninstall($packlist);
+
+ pm_to_blib({ 'lib/Foo/Bar.pm' => 'blib/lib/Foo/Bar.pm' });
+
+=head1 VERSION
+
+2.22
+
+=cut
+
+our $VERSION = '2.22'; # <-- do not forget to update the POD section just above this line!
+$VERSION = eval $VERSION;
+
+=pod
+
+=head1 DESCRIPTION
+
+Handles the installing and uninstalling of perl modules, scripts, man
+pages, etc...
+
+Both install() and uninstall() are specific to the way
+ExtUtils::MakeMaker handles the installation and deinstallation of
+perl modules. They are not designed as general purpose tools.
+
+On some operating systems such as Win32 installation may not be possible
+until after a reboot has occurred. This can have varying consequences:
+removing an old DLL does not impact programs using the new one, but if
+a new DLL cannot be installed properly until reboot then anything
+depending on it must wait. The package variable
+
+ $ExtUtils::Install::MUST_REBOOT
+
+is used to store this status.
+
+If this variable is true then such an operation has occurred and
+anything depending on this module cannot proceed until a reboot
+has occurred.
+
+If this value is defined but false then such an operation has
+occurred, but should not impact later operations.
+
+=begin _private
+
+=head2 _chmod($$;$)
+
+Wrapper to chmod() for debugging and error trapping.
+
+=head2 _warnonce(@)
+
+Warns about something only once.
+
+=head2 _choke(@)
+
+Dies with a special message.
+
+=end _private
+
+=cut
+
+BEGIN {
+ *_Is_VMS = $^O eq 'VMS' ? sub(){1} : sub(){0};
+ *_Is_Win32 = $^O eq 'MSWin32' ? sub(){1} : sub(){0};
+ *_Is_cygwin = $^O eq 'cygwin' ? sub(){1} : sub(){0};
+ *_CanMoveAtBoot = ($^O eq 'MSWin32' || $^O eq 'cygwin') ? sub(){1} : sub(){0};
+}
+
+my $Inc_uninstall_warn_handler;
+
+# install relative to here
+
+my $INSTALL_ROOT = $ENV{PERL_INSTALL_ROOT};
+my $INSTALL_QUIET = $ENV{PERL_INSTALL_QUIET};
+$INSTALL_QUIET = 1
+ if (!exists $ENV{PERL_INSTALL_QUIET} and
+ defined $ENV{MAKEFLAGS} and
+ $ENV{MAKEFLAGS} =~ /\b(s|silent|quiet)\b/);
+
+my $Curdir = File::Spec->curdir;
+
+sub _estr(@) {
+ return join "\n",'!' x 72,@_,'!' x 72,'';
+}
+
+{my %warned;
+sub _warnonce(@) {
+ my $first=shift;
+ my $msg=_estr "WARNING: $first",@_;
+ warn $msg unless $warned{$msg}++;
+}}
+
+sub _choke(@) {
+ my $first=shift;
+ my $msg=_estr "ERROR: $first",@_;
+ require Carp;
+ Carp::croak($msg);
+}
+
+sub _croak {
+ require Carp;
+ Carp::croak(@_);
+}
+sub _confess {
+ require Carp;
+ Carp::confess(@_);
+}
+
+sub _compare {
+ # avoid loading File::Compare in the common case
+ if (-f $_[1] && -s _ == -s $_[0]) {
+ require File::Compare;
+ return File::Compare::compare(@_);
+ }
+ return 1;
+}
+
+
+sub _chmod($$;$) {
+ my ( $mode, $item, $verbose )=@_;
+ $verbose ||= 0;
+ if (chmod $mode, $item) {
+ printf "chmod(0%o, %s)\n",$mode, $item if $verbose > 1;
+ } else {
+ my $err="$!";
+ _warnonce sprintf "WARNING: Failed chmod(0%o, %s): %s\n",
+ $mode, $item, $err
+ if -e $item;
+ }
+}
+
+=begin _private
+
+=head2 _move_file_at_boot( $file, $target, $moan )
+
+OS-Specific, Win32/Cygwin
+
+Schedules a file to be moved/renamed/deleted at next boot.
+$file should be a filespec of an existing file
+$target should be a ref to an array if the file is to be deleted
+otherwise it should be a filespec for a rename. If the file is existing
+it will be replaced.
+
+Sets $MUST_REBOOT to 0 to indicate a deletion operation has occurred
+and sets it to 1 to indicate that a move operation has been requested.
+
+returns 1 on success, on failure if $moan is false errors are fatal.
+If $moan is true then returns 0 on error and warns instead of dies.
+
+=end _private
+
+=cut
+
+{
+ my $Has_Win32API_File;
+ sub _move_file_at_boot { #XXX OS-SPECIFIC
+ my ( $file, $target, $moan )= @_;
+ _confess("Panic: Can't _move_file_at_boot on this platform!")
+ unless _CanMoveAtBoot;
+
+ my $descr= ref $target
+ ? "'$file' for deletion"
+ : "'$file' for installation as '$target'";
+
+ # *note* _CanMoveAtBoot is only incidentally the same condition as below
+ # this needs not hold true in the future.
+ $Has_Win32API_File = (_Is_Win32 || _Is_cygwin)
+ ? (eval {require Win32API::File; 1} || 0)
+ : 0 unless defined $Has_Win32API_File;
+ if ( ! $Has_Win32API_File ) {
+
+ my @msg=(
+ "Cannot schedule $descr at reboot.",
+ "Try installing Win32API::File to allow operations on locked files",
+ "to be scheduled during reboot. Or try to perform the operation by",
+ "hand yourself. (You may need to close other perl processes first)"
+ );
+ if ( $moan ) { _warnonce(@msg) } else { _choke(@msg) }
+ return 0;
+ }
+ my $opts= Win32API::File::MOVEFILE_DELAY_UNTIL_REBOOT();
+ $opts= $opts | Win32API::File::MOVEFILE_REPLACE_EXISTING()
+ unless ref $target;
+
+ _chmod( 0666, $file );
+ _chmod( 0666, $target ) unless ref $target;
+
+ if (Win32API::File::MoveFileEx( $file, $target, $opts )) {
+ $MUST_REBOOT ||= ref $target ? 0 : 1;
+ return 1;
+ } else {
+ my @msg=(
+ "MoveFileEx $descr at reboot failed: $^E",
+ "You may try to perform the operation by hand yourself. ",
+ "(You may need to close other perl processes first).",
+ );
+ if ( $moan ) { _warnonce(@msg) } else { _choke(@msg) }
+ }
+ return 0;
+ }
+}
+
+
+=begin _private
+
+=head2 _unlink_or_rename( $file, $tryhard, $installing )
+
+OS-Specific, Win32/Cygwin
+
+Tries to get a file out of the way by unlinking it or renaming it. On
+some OS'es (Win32 based) DLL files can end up locked such that they can
+be renamed but not deleted. Likewise sometimes a file can be locked such
+that it cant even be renamed or changed except at reboot. To handle
+these cases this routine finds a tempfile name that it can either rename
+the file out of the way or use as a proxy for the install so that the
+rename can happen later (at reboot).
+
+ $file : the file to remove.
+ $tryhard : should advanced tricks be used for deletion
+ $installing : we are not merely deleting but we want to overwrite
+
+When $tryhard is not true if the unlink fails its fatal. When $tryhard
+is true then the file is attempted to be renamed. The renamed file is
+then scheduled for deletion. If the rename fails then $installing
+governs what happens. If it is false the failure is fatal. If it is true
+then an attempt is made to schedule installation at boot using a
+temporary file to hold the new file. If this fails then a fatal error is
+thrown, if it succeeds it returns the temporary file name (which will be
+a derivative of the original in the same directory) so that the caller can
+use it to install under. In all other cases of success returns $file.
+On failure throws a fatal error.
+
+=end _private
+
+=cut
+
+sub _unlink_or_rename { #XXX OS-SPECIFIC
+ my ( $file, $tryhard, $installing )= @_;
+
+ # this chmod was originally unconditional. However, its not needed on
+ # POSIXy systems since permission to unlink a file is specified by the
+ # directory rather than the file; and in fact it screwed up hard- and
+ # symlinked files. Keep it for other platforms in case its still
+ # needed there.
+ if ($^O =~ /^(dos|os2|MSWin32|VMS)$/) {
+ _chmod( 0666, $file );
+ }
+ my $unlink_count = 0;
+ while (unlink $file) { $unlink_count++; }
+ return $file if $unlink_count > 0;
+ my $error="$!";
+
+ _choke("Cannot unlink '$file': $!")
+ unless _CanMoveAtBoot && $tryhard;
+
+ my $tmp= "AAA";
+ ++$tmp while -e "$file.$tmp";
+ $tmp= "$file.$tmp";
+
+ warn "WARNING: Unable to unlink '$file': $error\n",
+ "Going to try to rename it to '$tmp'.\n";
+
+ if ( rename $file, $tmp ) {
+ warn "Rename successful. Scheduling '$tmp'\nfor deletion at reboot.\n";
+ # when $installing we can set $moan to true.
+ # IOW, if we cant delete the renamed file at reboot its
+ # not the end of the world. The other cases are more serious
+ # and need to be fatal.
+ _move_file_at_boot( $tmp, [], $installing );
+ return $file;
+ } elsif ( $installing ) {
+ _warnonce("Rename failed: $!. Scheduling '$tmp'\nfor".
+ " installation as '$file' at reboot.\n");
+ _move_file_at_boot( $tmp, $file );
+ return $tmp;
+ } else {
+ _choke("Rename failed:$!", "Cannot proceed.");
+ }
+
+}
+
+=head1 Functions
+
+=begin _private
+
+=head2 _get_install_skip
+
+Handles loading the INSTALL.SKIP file. Returns an array of patterns to use.
+
+=cut
+
+sub _get_install_skip {
+ my ( $skip, $verbose )= @_;
+ if ($ENV{EU_INSTALL_IGNORE_SKIP}) {
+ print "EU_INSTALL_IGNORE_SKIP is set, ignore skipfile settings\n"
+ if $verbose>2;
+ return [];
+ }
+ if ( ! defined $skip ) {
+ print "Looking for install skip list\n"
+ if $verbose>2;
+ for my $file ( 'INSTALL.SKIP', $ENV{EU_INSTALL_SITE_SKIPFILE} ) {
+ next unless $file;
+ print "\tChecking for $file\n"
+ if $verbose>2;
+ if (-e $file) {
+ $skip= $file;
+ last;
+ }
+ }
+ }
+ if ($skip && !ref $skip) {
+ print "Reading skip patterns from '$skip'.\n"
+ if $verbose;
+ if (open my $fh,$skip ) {
+ my @patterns;
+ while (<$fh>) {
+ chomp;
+ next if /^\s*(?:#|$)/;
+ print "\tSkip pattern: $_\n" if $verbose>3;
+ push @patterns, $_;
+ }
+ $skip= \@patterns;
+ } else {
+ warn "Can't read skip file:'$skip':$!\n";
+ $skip=[];
+ }
+ } elsif ( UNIVERSAL::isa($skip,'ARRAY') ) {
+ print "Using array for skip list\n"
+ if $verbose>2;
+ } elsif ($verbose) {
+ print "No skip list found.\n"
+ if $verbose>1;
+ $skip= [];
+ }
+ warn "Got @{[0+@$skip]} skip patterns.\n"
+ if $verbose>3;
+ return $skip
+}
+
+=head2 _have_write_access
+
+Abstract a -w check that tries to use POSIX::access() if possible.
+
+=cut
+
+{
+ my $has_posix;
+ sub _have_write_access {
+ my $dir=shift;
+ unless (defined $has_posix) {
+ $has_posix = (!_Is_cygwin && !_Is_Win32
+ && eval { local $^W; require POSIX; 1} ) || 0;
+ }
+ if ($has_posix) {
+ return POSIX::access($dir, POSIX::W_OK());
+ } else {
+ return -w $dir;
+ }
+ }
+}
+
+=head2 _can_write_dir(C<$dir>)
+
+Checks whether a given directory is writable, taking account
+the possibility that the directory might not exist and would have to
+be created first.
+
+Returns a list, containing: C<($writable, $determined_by, @create)>
+
+C<$writable> says whether the directory is (hypothetically) writable
+
+C<$determined_by> is the directory the status was determined from. It will be
+either the C<$dir>, or one of its parents.
+
+C<@create> is a list of directories that would probably have to be created
+to make the requested directory. It may not actually be correct on
+relative paths with C<..> in them. But for our purposes it should work ok
+
+=cut
+
+sub _can_write_dir {
+ my $dir=shift;
+ return
+ unless defined $dir and length $dir;
+
+ my ($vol, $dirs, $file) = File::Spec->splitpath($dir,1);
+ my @dirs = File::Spec->splitdir($dirs);
+ unshift @dirs, File::Spec->curdir
+ unless File::Spec->file_name_is_absolute($dir);
+
+ my $path='';
+ my @make;
+ while (@dirs) {
+ if (_Is_VMS) {
+ $dir = File::Spec->catdir($vol,@dirs);
+ }
+ else {
+ $dir = File::Spec->catdir(@dirs);
+ $dir = File::Spec->catpath($vol,$dir,'')
+ if defined $vol and length $vol;
+ }
+ next if ( $dir eq $path );
+ if ( ! -e $dir ) {
+ unshift @make,$dir;
+ next;
+ }
+ if ( _have_write_access($dir) ) {
+ return 1,$dir,@make
+ } else {
+ return 0,$dir,@make
+ }
+ } continue {
+ pop @dirs;
+ }
+ return 0;
+}
+
+=head2 _mkpath($dir,$show,$mode,$verbose,$dry_run)
+
+Wrapper around File::Path::mkpath() to handle errors.
+
+If $verbose is true and >1 then additional diagnostics will be produced, also
+this will force $show to true.
+
+If $dry_run is true then the directory will not be created but a check will be
+made to see whether it would be possible to write to the directory, or that
+it would be possible to create the directory.
+
+If $dry_run is not true dies if the directory can not be created or is not
+writable.
+
+=cut
+
+sub _mkpath {
+ my ($dir,$show,$mode,$verbose,$dry_run)=@_;
+ if ( $verbose && $verbose > 1 && ! -d $dir) {
+ $show= 1;
+ printf "mkpath(%s,%d,%#o)\n", $dir, $show, $mode;
+ }
+ if (!$dry_run) {
+ my @created;
+ eval {
+ @created = File::Path::mkpath($dir,$show,$mode);
+ 1;
+ } or _choke("Can't create '$dir'","$@");
+ # if we created any directories, we were able to write and don't need
+ # extra checks
+ if (@created) {
+ return;
+ }
+ }
+ my ($can,$root,@make)=_can_write_dir($dir);
+ if (!$can) {
+ my @msg=(
+ "Can't create '$dir'",
+ $root ? "Do not have write permissions on '$root'"
+ : "Unknown Error"
+ );
+ if ($dry_run) {
+ _warnonce @msg;
+ } else {
+ _choke @msg;
+ }
+ } elsif ($show and $dry_run) {
+ print "$_\n" for @make;
+ }
+
+}
+
+=head2 _copy($from,$to,$verbose,$dry_run)
+
+Wrapper around File::Copy::copy to handle errors.
+
+If $verbose is true and >1 then additional diagnostics will be emitted.
+
+If $dry_run is true then the copy will not actually occur.
+
+Dies if the copy fails.
+
+=cut
+
+sub _copy {
+ my ( $from, $to, $verbose, $dry_run)=@_;
+ if ($verbose && $verbose>1) {
+ printf "copy(%s,%s)\n", $from, $to;
+ }
+ if (!$dry_run) {
+ File::Copy::copy($from,$to)
+ or _croak( _estr "ERROR: Cannot copy '$from' to '$to': $!" );
+ }
+}
+
+=pod
+
+=head2 _chdir($from)
+
+Wrapper around chdir to catch errors.
+
+If not called in void context returns the cwd from before the chdir.
+
+dies on error.
+
+=cut
+
+sub _chdir {
+ my ($dir)= @_;
+ my $ret;
+ if (defined wantarray) {
+ $ret= cwd;
+ }
+ chdir $dir
+ or _choke("Couldn't chdir to '$dir': $!");
+ return $ret;
+}
+
+=end _private
+
+=head2 install
+
+ # deprecated forms
+ install(\%from_to);
+ install(\%from_to, $verbose, $dry_run, $uninstall_shadows,
+ $skip, $always_copy, \%result);
+
+ # recommended form as of 1.47
+ install([
+ from_to => \%from_to,
+ verbose => 1,
+ dry_run => 0,
+ uninstall_shadows => 1,
+ skip => undef,
+ always_copy => 1,
+ result => \%install_results,
+ ]);
+
+
+Copies each directory tree of %from_to to its corresponding value
+preserving timestamps and permissions.
+
+There are two keys with a special meaning in the hash: "read" and
+"write". These contain packlist files. After the copying is done,
+install() will write the list of target files to $from_to{write}. If
+$from_to{read} is given the contents of this file will be merged into
+the written file. The read and the written file may be identical, but
+on AFS it is quite likely that people are installing to a different
+directory than the one where the files later appear.
+
+If $verbose is true, will print out each file removed. Default is
+false. This is "make install VERBINST=1". $verbose values going
+up to 5 show increasingly more diagnostics output.
+
+If $dry_run is true it will only print what it was going to do
+without actually doing it. Default is false.
+
+If $uninstall_shadows is true any differing versions throughout @INC
+will be uninstalled. This is "make install UNINST=1"
+
+As of 1.37_02 install() supports the use of a list of patterns to filter out
+files that shouldn't be installed. If $skip is omitted or undefined then
+install will try to read the list from INSTALL.SKIP in the CWD. This file is
+a list of regular expressions and is just like the MANIFEST.SKIP file used
+by L.
+
+A default site INSTALL.SKIP may be provided by setting then environment
+variable EU_INSTALL_SITE_SKIPFILE, this will only be used when there isn't a
+distribution specific INSTALL.SKIP. If the environment variable
+EU_INSTALL_IGNORE_SKIP is true then no install file filtering will be
+performed.
+
+If $skip is undefined then the skip file will be autodetected and used if it
+is found. If $skip is a reference to an array then it is assumed the array
+contains the list of patterns, if $skip is a true non reference it is
+assumed to be the filename holding the list of patterns, any other value of
+$skip is taken to mean that no install filtering should occur.
+
+B
+
+As of version 1.47 the following additions were made to the install interface.
+Note that the new argument style and use of the %result hash is recommended.
+
+The $always_copy parameter which when true causes files to be updated
+regardless as to whether they have changed, if it is defined but false then
+copies are made only if the files have changed, if it is undefined then the
+value of the environment variable EU_INSTALL_ALWAYS_COPY is used as default.
+
+The %result hash will be populated with the various keys/subhashes reflecting
+the install. Currently these keys and their structure are:
+
+ install => { $target => $source },
+ install_fail => { $target => $source },
+ install_unchanged => { $target => $source },
+
+ install_filtered => { $source => $pattern },
+
+ uninstall => { $uninstalled => $source },
+ uninstall_fail => { $uninstalled => $source },
+
+where C<$source> is the filespec of the file being installed. C<$target> is where
+it is being installed to, and C<$uninstalled> is any shadow file that is in C<@INC>
+or C<$ENV{PERL5LIB}> or other standard locations, and C<$pattern> is the pattern that
+caused a source file to be skipped. In future more keys will be added, such as to
+show created directories, however this requires changes in other modules and must
+therefore wait.
+
+These keys will be populated before any exceptions are thrown should there be an
+error.
+
+Note that all updates of the %result are additive, the hash will not be
+cleared before use, thus allowing status results of many installs to be easily
+aggregated.
+
+B
+
+If there is only one argument and it is a reference to an array then
+the array is assumed to contain a list of key-value pairs specifying
+the options. In this case the option "from_to" is mandatory. This style
+means that you do not have to supply a cryptic list of arguments and can
+use a self documenting argument list that is easier to understand.
+
+This is now the recommended interface to install().
+
+B
+
+If all actions were successful install will return a hashref of the results
+as described above for the $result parameter. If any action is a failure
+then install will die, therefore it is recommended to pass in the $result
+parameter instead of using the return value. If the result parameter is
+provided then the returned hashref will be the passed in hashref.
+
+=cut
+
+sub install { #XXX OS-SPECIFIC
+ my($from_to,$verbose,$dry_run,$uninstall_shadows,$skip,$always_copy,$result) = @_;
+ if (@_==1 and eval { 1+@$from_to }) {
+ my %opts = @$from_to;
+ $from_to = $opts{from_to}
+ or _confess("from_to is a mandatory parameter");
+ $verbose = $opts{verbose};
+ $dry_run = $opts{dry_run};
+ $uninstall_shadows = $opts{uninstall_shadows};
+ $skip = $opts{skip};
+ $always_copy = $opts{always_copy};
+ $result = $opts{result};
+ }
+
+ $result ||= {};
+ $verbose ||= 0;
+ $dry_run ||= 0;
+
+ $skip= _get_install_skip($skip,$verbose);
+ $always_copy = $ENV{EU_INSTALL_ALWAYS_COPY}
+ || $ENV{EU_ALWAYS_COPY}
+ || 0
+ unless defined $always_copy;
+
+ my(%from_to) = %$from_to;
+ my(%pack, $dir, %warned);
+ require ExtUtils::Packlist;
+ my($packlist) = ExtUtils::Packlist->new();
+
+ local(*DIR);
+ for (qw/read write/) {
+ $pack{$_}=$from_to{$_};
+ delete $from_to{$_};
+ }
+ my $tmpfile = install_rooted_file($pack{"read"});
+ $packlist->read($tmpfile) if (-f $tmpfile);
+ my $cwd = cwd();
+ my @found_files;
+ my %check_dirs;
+ require File::Find;
+
+ my $blib_lib = File::Spec->catdir('blib', 'lib');
+ my $blib_arch = File::Spec->catdir('blib', 'arch');
+
+ # File::Find seems to always be Unixy except on MacPerl :(
+ my $current_directory = $^O eq 'MacOS' ? $Curdir : '.';
+
+ MOD_INSTALL: foreach my $source (sort keys %from_to) {
+ #copy the tree to the target directory without altering
+ #timestamp and permission and remember for the .packlist
+ #file. The packlist file contains the absolute paths of the
+ #install locations. AFS users may call this a bug. We'll have
+ #to reconsider how to add the means to satisfy AFS users also.
+
+ #October 1997: we want to install .pm files into archlib if
+ #there are any files in arch. So we depend on having ./blib/arch
+ #hardcoded here.
+
+ my $targetroot = install_rooted_dir($from_to{$source});
+
+ if ($source eq $blib_lib and
+ exists $from_to{$blib_arch} and
+ directory_not_empty($blib_arch)
+ ){
+ $targetroot = install_rooted_dir($from_to{$blib_arch});
+ print "Files found in $blib_arch: installing files in $blib_lib into architecture dependent library tree\n";
+ }
+
+ next unless -d $source;
+ _chdir($source);
+ # 5.5.3's File::Find missing no_chdir option
+ # XXX OS-SPECIFIC
+ File::Find::find(sub {
+ my ($mode,$size,$atime,$mtime) = (stat)[2,7,8,9];
+
+ return if !-f _;
+ my $origfile = $_;
+
+ return if $origfile eq ".exists";
+ my $targetdir = File::Spec->catdir($targetroot, $File::Find::dir);
+ my $targetfile = File::Spec->catfile($targetdir, $origfile);
+ my $sourcedir = File::Spec->catdir($source, $File::Find::dir);
+ my $sourcefile = File::Spec->catfile($sourcedir, $origfile);
+
+ for my $pat (@$skip) {
+ if ( $sourcefile=~/$pat/ ) {
+ print "Skipping $targetfile (filtered)\n"
+ if $verbose>1;
+ $result->{install_filtered}{$sourcefile} = $pat;
+ return;
+ }
+ }
+ # we have to do this for back compat with old File::Finds
+ # and because the target is relative
+ my $save_cwd = File::Spec->catfile($cwd, $sourcedir);
+ _chdir($cwd);
+ my $diff = $always_copy || _compare($sourcefile, $targetfile);
+ $check_dirs{$targetdir}++
+ unless -w $targetfile;
+
+ push @found_files,
+ [ $diff, $File::Find::dir, $origfile,
+ $mode, $size, $atime, $mtime,
+ $targetdir, $targetfile, $sourcedir, $sourcefile,
+
+ ];
+ #restore the original directory we were in when File::Find
+ #called us so that it doesn't get horribly confused.
+ _chdir($save_cwd);
+ }, $current_directory );
+ _chdir($cwd);
+ }
+ foreach my $targetdir (sort keys %check_dirs) {
+ _mkpath( $targetdir, 0, 0755, $verbose, $dry_run );
+ }
+ foreach my $found (@found_files) {
+ my ($diff, $ffd, $origfile, $mode, $size, $atime, $mtime,
+ $targetdir, $targetfile, $sourcedir, $sourcefile)= @$found;
+
+ my $realtarget= $targetfile;
+ if ($diff) {
+ eval {
+ if (-f $targetfile) {
+ print "_unlink_or_rename($targetfile)\n" if $verbose>1;
+ $targetfile= _unlink_or_rename( $targetfile, 'tryhard', 'install' )
+ unless $dry_run;
+ } elsif ( ! -d $targetdir ) {
+ _mkpath( $targetdir, 0, 0755, $verbose, $dry_run );
+ }
+ print "Installing $targetfile\n";
+
+ _copy( $sourcefile, $targetfile, $verbose, $dry_run, );
+
+
+ #XXX OS-SPECIFIC
+ print "utime($atime,$mtime,$targetfile)\n" if $verbose>1;
+ utime($atime,$mtime + _Is_VMS,$targetfile) unless $dry_run>1;
+
+
+ $mode = 0444 | ( $mode & 0111 ? 0111 : 0 );
+ $mode = $mode | 0222
+ if $realtarget ne $targetfile;
+ _chmod( $mode, $targetfile, $verbose );
+ $result->{install}{$targetfile} = $sourcefile;
+ 1
+ } or do {
+ $result->{install_fail}{$targetfile} = $sourcefile;
+ die $@;
+ };
+ } else {
+ $result->{install_unchanged}{$targetfile} = $sourcefile;
+ print "Skipping $targetfile (unchanged)\n" if $verbose;
+ }
+
+ if ( $uninstall_shadows ) {
+ inc_uninstall($sourcefile,$ffd, $verbose,
+ $dry_run,
+ $realtarget ne $targetfile ? $realtarget : "",
+ $result);
+ }
+
+ # Record the full pathname.
+ $packlist->{$targetfile}++;
+ }
+
+ if ($pack{'write'}) {
+ $dir = install_rooted_dir(dirname($pack{'write'}));
+ _mkpath( $dir, 0, 0755, $verbose, $dry_run );
+ print "Writing $pack{'write'}\n" if $verbose;
+ $packlist->write(install_rooted_file($pack{'write'})) unless $dry_run;
+ }
+
+ _do_cleanup($verbose);
+ return $result;
+}
+
+=begin _private
+
+=head2 _do_cleanup
+
+Standardize finish event for after another instruction has occurred.
+Handles converting $MUST_REBOOT to a die for instance.
+
+=end _private
+
+=cut
+
+sub _do_cleanup {
+ my ($verbose) = @_;
+ if ($MUST_REBOOT) {
+ die _estr "Operation not completed! ",
+ "You must reboot to complete the installation.",
+ "Sorry.";
+ } elsif (defined $MUST_REBOOT & $verbose) {
+ warn _estr "Installation will be completed at the next reboot.\n",
+ "However it is not necessary to reboot immediately.\n";
+ }
+}
+
+=begin _undocumented
+
+=head2 install_rooted_file( $file )
+
+Returns $file, or catfile($INSTALL_ROOT,$file) if $INSTALL_ROOT
+is defined.
+
+=head2 install_rooted_dir( $dir )
+
+Returns $dir, or catdir($INSTALL_ROOT,$dir) if $INSTALL_ROOT
+is defined.
+
+=end _undocumented
+
+=cut
+
+sub install_rooted_file {
+ if (defined $INSTALL_ROOT) {
+ File::Spec->catfile($INSTALL_ROOT, $_[0]);
+ } else {
+ $_[0];
+ }
+}
+
+
+sub install_rooted_dir {
+ if (defined $INSTALL_ROOT) {
+ File::Spec->catdir($INSTALL_ROOT, $_[0]);
+ } else {
+ $_[0];
+ }
+}
+
+=begin _undocumented
+
+=head2 forceunlink( $file, $tryhard )
+
+Tries to delete a file. If $tryhard is true then we will use whatever
+devious tricks we can to delete the file. Currently this only applies to
+Win32 in that it will try to use Win32API::File to schedule a delete at
+reboot. A wrapper for _unlink_or_rename().
+
+=end _undocumented
+
+=cut
+
+sub forceunlink {
+ my ( $file, $tryhard )= @_; #XXX OS-SPECIFIC
+ _unlink_or_rename( $file, $tryhard, not("installing") );
+}
+
+=begin _undocumented
+
+=head2 directory_not_empty( $dir )
+
+Returns 1 if there is an .exists file somewhere in a directory tree.
+Returns 0 if there is not.
+
+=end _undocumented
+
+=cut
+
+sub directory_not_empty ($) {
+ my($dir) = @_;
+ my $files = 0;
+ require File::Find;
+ File::Find::find(sub {
+ return if $_ eq ".exists";
+ if (-f) {
+ $File::Find::prune++;
+ $files = 1;
+ }
+ }, $dir);
+ return $files;
+}
+
+=head2 install_default
+
+I
+
+ install_default();
+ install_default($fullext);
+
+Calls install() with arguments to copy a module from blib/ to the
+default site installation location.
+
+$fullext is the name of the module converted to a directory
+(ie. Foo::Bar would be Foo/Bar). If $fullext is not specified, it
+will attempt to read it from @ARGV.
+
+This is primarily useful for install scripts.
+
+B This function is not really useful because of the hard-coded
+install location with no way to control site vs core vs vendor
+directories and the strange way in which the module name is given.
+Consider its use discouraged.
+
+=cut
+
+sub install_default {
+ @_ < 2 or _croak("install_default should be called with 0 or 1 argument");
+ my $FULLEXT = @_ ? shift : $ARGV[0];
+ defined $FULLEXT or die "Do not know to where to write install log";
+ my $INST_LIB = File::Spec->catdir($Curdir,"blib","lib");
+ my $INST_ARCHLIB = File::Spec->catdir($Curdir,"blib","arch");
+ my $INST_BIN = File::Spec->catdir($Curdir,'blib','bin');
+ my $INST_SCRIPT = File::Spec->catdir($Curdir,'blib','script');
+ my $INST_MAN1DIR = File::Spec->catdir($Curdir,'blib','man1');
+ my $INST_MAN3DIR = File::Spec->catdir($Curdir,'blib','man3');
+
+ my @INST_HTML;
+ if($Config{installhtmldir}) {
+ my $INST_HTMLDIR = File::Spec->catdir($Curdir,'blib','html');
+ @INST_HTML = ($INST_HTMLDIR => $Config{installhtmldir});
+ }
+
+ install({
+ read => "$Config{sitearchexp}/auto/$FULLEXT/.packlist",
+ write => "$Config{installsitearch}/auto/$FULLEXT/.packlist",
+ $INST_LIB => (directory_not_empty($INST_ARCHLIB)) ?
+ $Config{installsitearch} :
+ $Config{installsitelib},
+ $INST_ARCHLIB => $Config{installsitearch},
+ $INST_BIN => $Config{installbin} ,
+ $INST_SCRIPT => $Config{installscript},
+ $INST_MAN1DIR => $Config{installman1dir},
+ $INST_MAN3DIR => $Config{installman3dir},
+ @INST_HTML,
+ },1,0,0);
+}
+
+
+=head2 uninstall
+
+ uninstall($packlist_file);
+ uninstall($packlist_file, $verbose, $dont_execute);
+
+Removes the files listed in a $packlist_file.
+
+If $verbose is true, will print out each file removed. Default is
+false.
+
+If $dont_execute is true it will only print what it was going to do
+without actually doing it. Default is false.
+
+=cut
+
+sub uninstall {
+ my($fil,$verbose,$dry_run) = @_;
+ $verbose ||= 0;
+ $dry_run ||= 0;
+
+ die _estr "ERROR: no packlist file found: '$fil'"
+ unless -f $fil;
+ # my $my_req = $self->catfile(qw(auto ExtUtils Install forceunlink.al));
+ # require $my_req; # Hairy, but for the first
+ require ExtUtils::Packlist;
+ my ($packlist) = ExtUtils::Packlist->new($fil);
+ foreach (sort(keys(%$packlist))) {
+ chomp;
+ print "unlink $_\n" if $verbose;
+ forceunlink($_,'tryhard') unless $dry_run;
+ }
+ print "unlink $fil\n" if $verbose;
+ forceunlink($fil, 'tryhard') unless $dry_run;
+ _do_cleanup($verbose);
+}
+
+=begin _undocumented
+
+=head2 inc_uninstall($filepath,$libdir,$verbose,$dry_run,$ignore,$results)
+
+Remove shadowed files. If $ignore is true then it is assumed to hold
+a filename to ignore. This is used to prevent spurious warnings from
+occurring when doing an install at reboot.
+
+We now only die when failing to remove a file that has precedence over
+our own, when our install has precedence we only warn.
+
+$results is assumed to contain a hashref which will have the keys
+'uninstall' and 'uninstall_fail' populated with keys for the files
+removed and values of the source files they would shadow.
+
+=end _undocumented
+
+=cut
+
+sub inc_uninstall {
+ my($filepath,$libdir,$verbose,$dry_run,$ignore,$results) = @_;
+ my($dir);
+ $ignore||="";
+ my $file = (File::Spec->splitpath($filepath))[2];
+ my %seen_dir = ();
+
+ my @PERL_ENV_LIB = split $Config{path_sep}, defined $ENV{'PERL5LIB'}
+ ? $ENV{'PERL5LIB'} : $ENV{'PERLLIB'} || '';
+
+ my @dirs=( @PERL_ENV_LIB,
+ @INC,
+ @Config{qw(archlibexp
+ privlibexp
+ sitearchexp
+ sitelibexp)});
+
+ #warn join "\n","---",@dirs,"---";
+ my $seen_ours;
+ foreach $dir ( @dirs ) {
+ my $canonpath = _Is_VMS ? $dir : File::Spec->canonpath($dir);
+ next if $canonpath eq $Curdir;
+ next if $seen_dir{$canonpath}++;
+ my $targetfile = File::Spec->catfile($canonpath,$libdir,$file);
+ next unless -f $targetfile;
+
+ # The reason why we compare file's contents is, that we cannot
+ # know, which is the file we just installed (AFS). So we leave
+ # an identical file in place
+ my $diff = _compare($filepath,$targetfile);
+
+ print "#$file and $targetfile differ\n" if $diff && $verbose > 1;
+
+ if (!$diff or $targetfile eq $ignore) {
+ $seen_ours = 1;
+ next;
+ }
+ if ($dry_run) {
+ $results->{uninstall}{$targetfile} = $filepath;
+ if ($verbose) {
+ $Inc_uninstall_warn_handler ||= ExtUtils::Install::Warn->new();
+ $libdir =~ s|^\./||s ; # That's just cosmetics, no need to port. It looks prettier.
+ $Inc_uninstall_warn_handler->add(
+ File::Spec->catfile($libdir, $file),
+ $targetfile
+ );
+ }
+ # if not verbose, we just say nothing
+ } else {
+ print "Unlinking $targetfile (shadowing?)\n" if $verbose;
+ eval {
+ die "Fake die for testing"
+ if $ExtUtils::Install::Testing and
+ ucase(File::Spec->canonpath($ExtUtils::Install::Testing)) eq ucase($targetfile);
+ forceunlink($targetfile,'tryhard');
+ $results->{uninstall}{$targetfile} = $filepath;
+ 1;
+ } or do {
+ $results->{fail_uninstall}{$targetfile} = $filepath;
+ if ($seen_ours) {
+ warn "Failed to remove probably harmless shadow file '$targetfile'\n";
+ } else {
+ die "$@\n";
+ }
+ };
+ }
+ }
+}
+
+=begin _undocumented
+
+=head2 run_filter($cmd,$src,$dest)
+
+Filter $src using $cmd into $dest.
+
+=end _undocumented
+
+=cut
+
+sub run_filter {
+ my ($cmd, $src, $dest) = @_;
+ local(*CMD, *SRC);
+ open(CMD, "|$cmd >$dest") || die "Cannot fork: $!";
+ open(SRC, $src) || die "Cannot open $src: $!";
+ my $buf;
+ my $sz = 1024;
+ while (my $len = sysread(SRC, $buf, $sz)) {
+ syswrite(CMD, $buf, $len);
+ }
+ close SRC;
+ close CMD or die "Filter command '$cmd' failed for $src";
+}
+
+=head2 pm_to_blib
+
+ pm_to_blib(\%from_to);
+ pm_to_blib(\%from_to, $autosplit_dir);
+ pm_to_blib(\%from_to, $autosplit_dir, $filter_cmd);
+
+Copies each key of %from_to to its corresponding value efficiently.
+If an $autosplit_dir is provided, all .pm files will be autosplit into it.
+Any destination directories are created.
+
+$filter_cmd is an optional shell command to run each .pm file through
+prior to splitting and copying. Input is the contents of the module,
+output the new module contents.
+
+You can have an environment variable PERL_INSTALL_ROOT set which will
+be prepended as a directory to each installed file (and directory).
+
+By default verbose output is generated, setting the PERL_INSTALL_QUIET
+environment variable will silence this output.
+
+=cut
+
+sub pm_to_blib {
+ my($fromto,$autodir,$pm_filter) = @_;
+
+ my %dirs;
+ _mkpath($autodir,0,0755) if defined $autodir;
+ while(my($from, $to) = each %$fromto) {
+ if( -f $to && -s $from == -s $to && -M $to < -M $from ) {
+ print "Skip $to (unchanged)\n" unless $INSTALL_QUIET;
+ next;
+ }
+
+ # When a pm_filter is defined, we need to pre-process the source first
+ # to determine whether it has changed or not. Therefore, only perform
+ # the comparison check when there's no filter to be ran.
+ # -- RAM, 03/01/2001
+
+ my $need_filtering = defined $pm_filter && length $pm_filter &&
+ $from =~ /\.pm$/;
+
+ if (!$need_filtering && !_compare($from,$to)) {
+ print "Skip $to (unchanged)\n" unless $INSTALL_QUIET;
+ next;
+ }
+ if (-f $to){
+ # we wont try hard here. its too likely to mess things up.
+ forceunlink($to);
+ } else {
+ my $dirname = dirname($to);
+ if (!$dirs{$dirname}++) {
+ _mkpath($dirname,0,0755);
+ }
+ }
+ if ($need_filtering) {
+ run_filter($pm_filter, $from, $to);
+ print "$pm_filter <$from >$to\n";
+ } else {
+ _copy( $from, $to );
+ print "cp $from $to\n" unless $INSTALL_QUIET;
+ }
+ my($mode,$atime,$mtime) = (stat $from)[2,8,9];
+ utime($atime,$mtime+_Is_VMS,$to);
+ _chmod(0444 | ( $mode & 0111 ? 0111 : 0 ),$to);
+ next unless $from =~ /\.pm$/;
+ _autosplit($to,$autodir) if defined $autodir;
+ }
+}
+
+=begin _private
+
+=head2 _autosplit
+
+From 1.0307 back, AutoSplit will sometimes leave an open filehandle to
+the file being split. This causes problems on systems with mandatory
+locking (ie. Windows). So we wrap it and close the filehandle.
+
+=end _private
+
+=cut
+
+sub _autosplit { #XXX OS-SPECIFIC
+ require AutoSplit;
+ my $retval = AutoSplit::autosplit(@_);
+ close *AutoSplit::IN if defined *AutoSplit::IN{IO};
+
+ return $retval;
+}
+
+
+package ExtUtils::Install::Warn;
+
+sub new { bless {}, shift }
+
+sub add {
+ my($self,$file,$targetfile) = @_;
+ push @{$self->{$file}}, $targetfile;
+}
+
+sub DESTROY {
+ unless(defined $INSTALL_ROOT) {
+ my $self = shift;
+ my($file,$i,$plural);
+ foreach $file (sort keys %$self) {
+ $plural = @{$self->{$file}} > 1 ? "s" : "";
+ print "## Differing version$plural of $file found. You might like to\n";
+ for (0..$#{$self->{$file}}) {
+ print "rm ", $self->{$file}[$_], "\n";
+ $i++;
+ }
+ }
+ $plural = $i>1 ? "all those files" : "this file";
+ my $inst = (_invokant() eq 'ExtUtils::MakeMaker')
+ ? ( $Config::Config{make} || 'make' ).' install'
+ . ( ExtUtils::Install::_Is_VMS ? '/MACRO="UNINST"=1' : ' UNINST=1' )
+ : './Build install uninst=1';
+ print "## Running '$inst' will unlink $plural for you.\n";
+ }
+}
+
+=begin _private
+
+=head2 _invokant
+
+Does a heuristic on the stack to see who called us for more intelligent
+error messages. Currently assumes we will be called only by Module::Build
+or by ExtUtils::MakeMaker.
+
+=end _private
+
+=cut
+
+sub _invokant {
+ my @stack;
+ my $frame = 0;
+ while (my $file = (caller($frame++))[1]) {
+ push @stack, (File::Spec->splitpath($file))[2];
+ }
+
+ my $builder;
+ my $top = pop @stack;
+ if ($top =~ /^Build/i || exists($INC{'Module/Build.pm'})) {
+ $builder = 'Module::Build';
+ } else {
+ $builder = 'ExtUtils::MakeMaker';
+ }
+ return $builder;
+}
+
+=head1 ENVIRONMENT
+
+=over 4
+
+=item B
+
+Will be prepended to each install path.
+
+=item B
+
+Will prevent the automatic use of INSTALL.SKIP as the install skip file.
+
+=item B
+
+If there is no INSTALL.SKIP file in the make directory then this value
+can be used to provide a default.
+
+=item B
+
+If this environment variable is true then normal install processes will
+always overwrite older identical files during the install process.
+
+Note that the alias EU_ALWAYS_COPY will be supported if EU_INSTALL_ALWAYS_COPY
+is not defined until at least the 1.50 release. Please ensure you use the
+correct EU_INSTALL_ALWAYS_COPY.
+
+=back
+
+=head1 AUTHOR
+
+Original author lost in the mists of time. Probably the same as Makemaker.
+
+Production release currently maintained by demerphq C,
+extensive changes by Michael G. Schwern.
+
+Send bug reports via http://rt.cpan.org/. Please send your
+generated Makefile along with your report.
+
+=head1 LICENSE
+
+This program is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+See L
+
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/Installed.pm b/src/main/perl/lib/ExtUtils/Installed.pm
new file mode 100644
index 000000000..c82861bd1
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Installed.pm
@@ -0,0 +1,469 @@
+use strict;
+package ExtUtils::Installed;
+
+#use warnings; # XXX requires 5.6
+use Carp qw();
+use ExtUtils::Packlist;
+use ExtUtils::MakeMaker;
+use Config;
+use File::Find;
+use File::Basename;
+use File::Spec;
+
+my $Is_VMS = $^O eq 'VMS';
+my $DOSISH = ($^O =~ /^(MSWin\d\d|os2|dos|mint)$/);
+
+require VMS::Filespec if $Is_VMS;
+
+our $VERSION = '2.22';
+$VERSION = eval $VERSION;
+
+sub _is_prefix {
+ my ($self, $path, $prefix) = @_;
+ return unless defined $prefix && defined $path;
+
+ if( $Is_VMS ) {
+ $prefix = VMS::Filespec::unixify($prefix);
+ $path = VMS::Filespec::unixify($path);
+ }
+
+ # Unix path normalization.
+ $prefix = File::Spec->canonpath($prefix);
+
+ return 1 if substr($path, 0, length($prefix)) eq $prefix;
+
+ if ($DOSISH) {
+ $path =~ s|\\|/|g;
+ $prefix =~ s|\\|/|g;
+ return 1 if $path =~ m{^\Q$prefix\E}i;
+ }
+ return(0);
+}
+
+sub _is_doc {
+ my ($self, $path) = @_;
+
+ my $man1dir = $self->{':private:'}{Config}{man1direxp};
+ my $man3dir = $self->{':private:'}{Config}{man3direxp};
+ return(($man1dir && $self->_is_prefix($path, $man1dir))
+ ||
+ ($man3dir && $self->_is_prefix($path, $man3dir))
+ ? 1 : 0)
+}
+
+sub _is_type {
+ my ($self, $path, $type) = @_;
+ return 1 if $type eq "all";
+
+ return($self->_is_doc($path)) if $type eq "doc";
+ my $conf= $self->{':private:'}{Config};
+ if ($type eq "prog") {
+ return($self->_is_prefix($path, $conf->{prefix} || $conf->{prefixexp})
+ && !($self->_is_doc($path)) ? 1 : 0);
+ }
+ return(0);
+}
+
+sub _is_under {
+ my ($self, $path, @under) = @_;
+ $under[0] = "" if (! @under);
+ foreach my $dir (@under) {
+ return(1) if ($self->_is_prefix($path, $dir));
+ }
+
+ return(0);
+}
+
+sub _fix_dirs {
+ my ($self, @dirs)= @_;
+ # File::Find does not know how to deal with VMS filepaths.
+ if( $Is_VMS ) {
+ $_ = VMS::Filespec::unixify($_)
+ for @dirs;
+ }
+
+ if ($DOSISH) {
+ s|\\|/|g for @dirs;
+ }
+ return wantarray ? @dirs : $dirs[0];
+}
+
+sub _make_entry {
+ my ($self, $module, $packlist_file, $modfile)= @_;
+
+ my $data= {
+ module => $module,
+ packlist => scalar(ExtUtils::Packlist->new($packlist_file)),
+ packlist_file => $packlist_file,
+ };
+
+ if (!$modfile) {
+ $data->{version} = $self->{':private:'}{Config}{version};
+ } else {
+ $data->{modfile} = $modfile;
+ # Find the top-level module file in @INC
+ $data->{version} = '';
+ foreach my $dir (@{$self->{':private:'}{INC}}) {
+ my $p = File::Spec->catfile($dir, $modfile);
+ if (-r $p) {
+ $module = _module_name($p, $module) if $Is_VMS;
+
+ $data->{version} = MM->parse_version($p);
+ $data->{version_from} = $p;
+ $data->{packlist_valid} = exists $data->{packlist}{$p};
+ last;
+ }
+ }
+ }
+ $self->{$module}= $data;
+}
+
+our $INSTALLED;
+sub new {
+ my ($class) = shift(@_);
+ $class = ref($class) || $class;
+
+ my %args = @_;
+
+ return $INSTALLED if $INSTALLED and ($args{default_get} || $args{default});
+
+ my $self = bless {}, $class;
+
+ $INSTALLED= $self if $args{default_set} || $args{default};
+
+
+ if ($args{config_override}) {
+ eval {
+ $self->{':private:'}{Config} = { %{$args{config_override}} };
+ } or Carp::croak(
+ "The 'config_override' parameter must be a hash reference."
+ );
+ }
+ else {
+ $self->{':private:'}{Config} = \%Config;
+ }
+
+ for my $tuple ([inc_override => INC => [ @INC ] ],
+ [ extra_libs => EXTRA => [] ])
+ {
+ my ($arg,$key,$val)=@$tuple;
+ if ( $args{$arg} ) {
+ eval {
+ $self->{':private:'}{$key} = [ @{$args{$arg}} ];
+ } or Carp::croak(
+ "The '$arg' parameter must be an array reference."
+ );
+ }
+ elsif ($val) {
+ $self->{':private:'}{$key} = $val;
+ }
+ }
+ {
+ my %dupe;
+ @{$self->{':private:'}{LIBDIRS}} =
+ grep { $_ ne '.' || ! $args{skip_cwd} }
+ grep { -e $_ && !$dupe{$_}++ }
+ @{$self->{':private:'}{EXTRA}}, @{$self->{':private:'}{INC}};
+ }
+
+ my @dirs= $self->_fix_dirs(@{$self->{':private:'}{LIBDIRS}});
+
+ # Read the core packlist
+ my $archlib = $self->_fix_dirs($self->{':private:'}{Config}{archlibexp});
+ $self->_make_entry("Perl",File::Spec->catfile($archlib, '.packlist'));
+
+ my $root;
+ # Read the module packlists
+ my $sub = sub {
+ # Only process module .packlists
+ return if $_ ne ".packlist" || $File::Find::dir eq $archlib;
+
+ # Hack of the leading bits of the paths & convert to a module name
+ my $module = $File::Find::name;
+ my $found = $module =~ s!^.*?/auto/(.*)/.packlist!$1!s
+ or do {
+ # warn "Woah! \$_=$_\n\$module=$module\n\$File::Find::dir=$File::Find::dir\n",
+ # join ("\n",@dirs);
+ return;
+ };
+
+ my $modfile = "$module.pm";
+ $module =~ s!/!::!g;
+
+ return if $self->{$module}; #shadowing?
+ $self->_make_entry($module,$File::Find::name,$modfile);
+ };
+ while (@dirs) {
+ $root= shift @dirs;
+ next if !-d $root;
+ find($sub,$root);
+ }
+
+ return $self;
+}
+
+# VMS's non-case preserving file-system means the package name can't
+# be reconstructed from the filename.
+sub _module_name {
+ my($file, $orig_module) = @_;
+
+ my $module = '';
+ if (open PACKFH, $file) {
+ while () {
+ if (/package\s+(\S+)\s*;/) {
+ my $pack = $1;
+ # Make a sanity check, that lower case $module
+ # is identical to lowercase $pack before
+ # accepting it
+ if (lc($pack) eq lc($orig_module)) {
+ $module = $pack;
+ last;
+ }
+ }
+ }
+ close PACKFH;
+ }
+
+ print STDERR "Couldn't figure out the package name for $file\n"
+ unless $module;
+
+ return $module;
+}
+
+sub modules {
+ my ($self) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+
+ # Bug/feature of sort in scalar context requires this.
+ return wantarray
+ ? sort grep { not /^:private:$/ } keys %$self
+ : grep { not /^:private:$/ } keys %$self;
+}
+
+sub files {
+ my ($self, $module, $type, @under) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+
+ # Validate arguments
+ Carp::croak("$module is not installed") if (! exists($self->{$module}));
+ $type = "all" if (! defined($type));
+ Carp::croak('type must be "all", "prog" or "doc"')
+ if ($type ne "all" && $type ne "prog" && $type ne "doc");
+
+ my (@files);
+ foreach my $file (keys(%{$self->{$module}{packlist}})) {
+ push(@files, $file)
+ if ($self->_is_type($file, $type) &&
+ $self->_is_under($file, @under));
+ }
+ return(@files);
+}
+
+sub directories {
+ my ($self, $module, $type, @under) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ my (%dirs);
+ foreach my $file ($self->files($module, $type, @under)) {
+ $dirs{dirname($file)}++;
+ }
+ return sort keys %dirs;
+}
+
+sub directory_tree {
+ my ($self, $module, $type, @under) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ my (%dirs);
+ foreach my $dir ($self->directories($module, $type, @under)) {
+ $dirs{$dir}++;
+ my ($last) = ("");
+ while ($last ne $dir) {
+ $last = $dir;
+ $dir = dirname($dir);
+ last if !$self->_is_under($dir, @under);
+ $dirs{$dir}++;
+ }
+ }
+ return(sort(keys(%dirs)));
+}
+
+sub validate {
+ my ($self, $module, $remove) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ Carp::croak("$module is not installed") if (! exists($self->{$module}));
+ return($self->{$module}{packlist}->validate($remove));
+}
+
+sub packlist {
+ my ($self, $module) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ Carp::croak("$module is not installed") if (! exists($self->{$module}));
+ return($self->{$module}{packlist});
+}
+
+sub version {
+ my ($self, $module) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ Carp::croak("$module is not installed") if (! exists($self->{$module}));
+ return($self->{$module}{version});
+}
+
+sub _debug_dump {
+ my ($self, $module) = @_;
+ $self= $self->new(default=>1) if !ref $self;
+ local $self->{":private:"}{Config};
+ require Data::Dumper;
+ print Data::Dumper->new([$self])->Sortkeys(1)->Indent(1)->Dump();
+}
+
+
+1;
+
+__END__
+
+=head1 NAME
+
+ExtUtils::Installed - Inventory management of installed modules
+
+=head1 SYNOPSIS
+
+ use ExtUtils::Installed;
+ my ($inst) = ExtUtils::Installed->new( skip_cwd => 1 );
+ my (@modules) = $inst->modules();
+ my (@missing) = $inst->validate("DBI");
+ my $all_files = $inst->files("DBI");
+ my $files_below_usr_local = $inst->files("DBI", "all", "/usr/local");
+ my $all_dirs = $inst->directories("DBI");
+ my $dirs_below_usr_local = $inst->directory_tree("DBI", "prog");
+ my $packlist = $inst->packlist("DBI");
+
+=head1 DESCRIPTION
+
+ExtUtils::Installed provides a standard way to find out what core and module
+files have been installed. It uses the information stored in .packlist files
+created during installation to provide this information. In addition it
+provides facilities to classify the installed files and to extract directory
+information from the .packlist files.
+
+=head1 USAGE
+
+The new() function searches for all the installed .packlists on the system, and
+stores their contents. The .packlists can be queried with the functions
+described below. Where it searches by default is determined by the settings found
+in C<%Config::Config>, and what the value is of the PERL5LIB environment variable.
+
+=head1 METHODS
+
+Unless specified otherwise all method can be called as class methods, or as object
+methods. If called as class methods then the "default" object will be used, and if
+necessary created using the current processes %Config and @INC. See the
+'default' option to new() for details.
+
+
+=over 4
+
+=item new()
+
+This takes optional named parameters. Without parameters, this
+searches for all the installed .packlists on the system using
+information from C<%Config::Config> and the default module search
+paths C<@INC>. The packlists are read using the
+L module.
+
+If the named parameter C is true, the current directory C<.> will
+be stripped from C<@INC> before searching for .packlists. This keeps
+ExtUtils::Installed from finding modules installed in other perls that
+happen to be located below the current directory.
+
+If the named parameter C is specified,
+it should be a reference to a hash which contains all information
+usually found in C<%Config::Config>. For example, you can obtain
+the configuration information for a separate perl installation and
+pass that in.
+
+ my $yoda_cfg = get_fake_config('yoda');
+ my $yoda_inst =
+ ExtUtils::Installed->new(config_override=>$yoda_cfg);
+
+Similarly, the parameter C may be a reference to an
+array which is used in place of the default module search paths
+from C<@INC>.
+
+ use Config;
+ my @dirs = split(/\Q$Config{path_sep}\E/, $ENV{PERL5LIB});
+ my $p5libs = ExtUtils::Installed->new(inc_override=>\@dirs);
+
+B: You probably do not want to use these options alone, almost always
+you will want to set both together.
+
+The parameter C can be used to specify B paths to
+search for installed modules. For instance
+
+ my $installed =
+ ExtUtils::Installed->new(extra_libs=>["/my/lib/path"]);
+
+This should only be necessary if F is not in PERL5LIB.
+
+Finally there is the 'default', and the related 'default_get' and 'default_set'
+options. These options control the "default" object which is provided by the
+class interface to the methods. Setting C to true tells the constructor
+to return the default object if it is defined. Setting C to true tells
+the constructor to make the default object the constructed object. Setting the
+C option is like setting both to true. This is used primarily internally
+and probably isn't interesting to any real user.
+
+=item modules()
+
+This returns a list of the names of all the installed modules. The perl 'core'
+is given the special name 'Perl'.
+
+=item files()
+
+This takes one mandatory parameter, the name of a module. It returns a list of
+all the filenames from the package. To obtain a list of core perl files, use
+the module name 'Perl'. Additional parameters are allowed. The first is one
+of the strings "prog", "doc" or "all", to select either just program files,
+just manual files or all files. The remaining parameters are a list of
+directories. The filenames returned will be restricted to those under the
+specified directories.
+
+=item directories()
+
+This takes one mandatory parameter, the name of a module. It returns a list of
+all the directories from the package. Additional parameters are allowed. The
+first is one of the strings "prog", "doc" or "all", to select either just
+program directories, just manual directories or all directories. The remaining
+parameters are a list of directories. The directories returned will be
+restricted to those under the specified directories. This method returns only
+the leaf directories that contain files from the specified module.
+
+=item directory_tree()
+
+This is identical in operation to directories(), except that it includes all the
+intermediate directories back up to the specified directories.
+
+=item validate()
+
+This takes one mandatory parameter, the name of a module. It checks that all
+the files listed in the modules .packlist actually exist, and returns a list of
+any missing files. If an optional second argument which evaluates to true is
+given any missing files will be removed from the .packlist
+
+=item packlist()
+
+This returns the ExtUtils::Packlist object for the specified module.
+
+=item version()
+
+This returns the version number for the specified module.
+
+=back
+
+=head1 EXAMPLE
+
+See the example in L.
+
+=head1 AUTHOR
+
+Alan Burlison
+
+=cut
diff --git a/src/main/perl/lib/ExtUtils/Liblist.pm b/src/main/perl/lib/ExtUtils/Liblist.pm
new file mode 100644
index 000000000..8ddf119da
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Liblist.pm
@@ -0,0 +1,288 @@
+package ExtUtils::Liblist;
+
+use strict;
+use warnings;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+use File::Spec;
+require ExtUtils::Liblist::Kid;
+our @ISA = qw(ExtUtils::Liblist::Kid File::Spec);
+
+# Backwards compatibility with old interface.
+sub ext {
+ goto &ExtUtils::Liblist::Kid::ext;
+}
+
+sub lsdir {
+ shift;
+ my $rex = qr/$_[1]/;
+ opendir my $dir_fh, $_[0];
+ my @out = grep /$rex/, readdir $dir_fh;
+ closedir $dir_fh;
+ return @out;
+}
+
+__END__
+
+=head1 NAME
+
+ExtUtils::Liblist - determine libraries to use and how to use them
+
+=head1 SYNOPSIS
+
+ require ExtUtils::Liblist;
+
+ $MM->ext($potential_libs, $verbose, $need_names);
+
+ # Usually you can get away with:
+ ExtUtils::Liblist->ext($potential_libs, $verbose, $need_names)
+
+=head1 DESCRIPTION
+
+This utility takes a list of libraries in the form C<-llib1 -llib2
+-llib3> and returns lines suitable for inclusion in an extension
+Makefile. Extra library paths may be included with the form
+C<-L/another/path> this will affect the searches for all subsequent
+libraries.
+
+It returns an array of four or five scalar values: EXTRALIBS,
+BSLOADLIBS, LDLOADLIBS, LD_RUN_PATH, and, optionally, a reference to
+the array of the filenames of actual libraries. Some of these don't
+mean anything unless on Unix. See the details about those platform
+specifics below. The list of the filenames is returned only if
+$need_names argument is true.
+
+Dependent libraries can be linked in one of three ways:
+
+=over 2
+
+=item * For static extensions
+
+by the ld command when the perl binary is linked with the extension
+library. See EXTRALIBS below.
+
+=item * For dynamic extensions at build/link time
+
+by the ld command when the shared object is built/linked. See
+LDLOADLIBS below.
+
+=item * For dynamic extensions at load time
+
+by the DynaLoader when the shared object is loaded. See BSLOADLIBS
+below.
+
+=back
+
+=head2 EXTRALIBS
+
+List of libraries that need to be linked with when linking a perl
+binary which includes this extension. Only those libraries that
+actually exist are included. These are written to a file and used
+when linking perl.
+
+=head2 LDLOADLIBS and LD_RUN_PATH
+
+List of those libraries which can or must be linked into the shared
+library when created using ld. These may be static or dynamic
+libraries. LD_RUN_PATH is a colon separated list of the directories
+in LDLOADLIBS. It is passed as an environment variable to the process
+that links the shared library.
+
+=head2 BSLOADLIBS
+
+List of those libraries that are needed but can be linked in
+dynamically at run time on this platform. SunOS/Solaris does not need
+this because ld records the information (from LDLOADLIBS) into the
+object file. This list is used to create a .bs (bootstrap) file.
+
+=head1 PORTABILITY
+
+This module deals with a lot of system dependencies and has quite a
+few architecture specific Cs in the code.
+
+=head2 VMS implementation
+
+The version of ext() which is executed under VMS differs from the
+Unix-OS/2 version in several respects:
+
+=over 2
+
+=item *
+
+Input library and path specifications are accepted with or without the
+C<-l> and C<-L> prefixes used by Unix linkers. If neither prefix is
+present, a token is considered a directory to search if it is in fact
+a directory, and a library to search for otherwise. Authors who wish
+their extensions to be portable to Unix or OS/2 should use the Unix
+prefixes, since the Unix-OS/2 version of ext() requires them.
+
+=item *
+
+Wherever possible, shareable images are preferred to object libraries,
+and object libraries to plain object files. In accordance with VMS
+naming conventions, ext() looks for files named Ishr and Irtl;
+it also looks for Ilib and libI to accommodate Unix conventions
+used in some ported software.
+
+=item *
+
+For each library that is found, an appropriate directive for a linker options
+file is generated. The return values are space-separated strings of
+these directives, rather than elements used on the linker command line.
+
+=item *
+
+LDLOADLIBS contains both the libraries found based on C<$potential_libs> and
+the CRTLs, if any, specified in Config.pm. EXTRALIBS contains just those
+libraries found based on C<$potential_libs>. BSLOADLIBS and LD_RUN_PATH
+are always empty.
+
+=back
+
+In addition, an attempt is made to recognize several common Unix library
+names, and filter them out or convert them to their VMS equivalents, as
+appropriate.
+
+In general, the VMS version of ext() should properly handle input from
+extensions originally designed for a Unix or VMS environment. If you
+encounter problems, or discover cases where the search could be improved,
+please let us know.
+
+=head2 Win32 implementation
+
+The version of ext() which is executed under Win32 differs from the
+Unix-OS/2 version in several respects:
+
+=over 2
+
+=item *
+
+If C<$potential_libs> is empty, the return value will be empty.
+Otherwise, the libraries specified by C<$Config{perllibs}> (see Config.pm)
+will be appended to the list of C<$potential_libs>. The libraries
+will be searched for in the directories specified in C<$potential_libs>,
+C<$Config{libpth}>, and in C<$Config{installarchlib}/CORE>.
+For each library that is found, a space-separated list of fully qualified
+library pathnames is generated.
+
+=item *
+
+Input library and path specifications are accepted with or without the
+C<-l> and C<-L> prefixes used by Unix linkers.
+
+An entry of the form C<-La:\foo> specifies the C directory to look
+for the libraries that follow.
+
+An entry of the form C<-lfoo> specifies the library C, which may be
+spelled differently depending on what kind of compiler you are using. If
+you are using GCC, it gets translated to C, but for other win32
+compilers, it becomes C. If no files are found by those translated
+names, one more attempt is made to find them using either C or
+C, depending on whether GCC or some other win32 compiler is
+being used, respectively.
+
+If neither the C<-L> or C<-l> prefix is present in an entry, the entry is
+considered a directory to search if it is in fact a directory, and a
+library to search for otherwise. The C<$Config{lib_ext}> suffix will
+be appended to any entries that are not directories and don't already have
+the suffix.
+
+Note that the C<-L> and C<-l> prefixes are B, but authors
+who wish their extensions to be portable to Unix or OS/2 should use the
+prefixes, since the Unix-OS/2 version of ext() requires them.
+
+=item *
+
+Entries cannot be plain object files, as many Win32 compilers will
+not handle object files in the place of libraries.
+
+=item *
+
+Entries in C<$potential_libs> beginning with a colon and followed by
+alphanumeric characters are treated as flags. Unknown flags will be ignored.
+
+An entry that matches C disables the appending of default
+libraries found in C<$Config{perllibs}> (this should be only needed very rarely).
+
+An entry that matches C disables all searching for
+the libraries specified after it. Translation of C<-Lfoo> and
+C<-lfoo> still happens as appropriate (depending on compiler being used,
+as reflected by C<$Config{cc}>), but the entries are not verified to be
+valid files or directories.
+
+An entry that matches C reenables searching for
+the libraries specified after it. You can put it at the end to
+enable searching for default libraries specified by C<$Config{perllibs}>.
+
+=item *
+
+The libraries specified may be a mixture of static libraries and
+import libraries (to link with DLLs). Since both kinds are used
+pretty transparently on the Win32 platform, we do not attempt to
+distinguish between them.
+
+=item *
+
+LDLOADLIBS and EXTRALIBS are always identical under Win32, and BSLOADLIBS
+and LD_RUN_PATH are always empty (this may change in future).
+
+=item *
+
+You must make sure that any paths and path components are properly
+surrounded with double-quotes if they contain spaces. For example,
+C<$potential_libs> could be (literally):
+
+ "-Lc:\Program Files\vc\lib" msvcrt.lib "la test\foo bar.lib"
+
+Note how the first and last entries are protected by quotes in order
+to protect the spaces.
+
+=item *
+
+Since this module is most often used only indirectly from extension
+C files, here is an example C entry to add
+a library to the build process for an extension:
+
+ LIBS => ['-lgl']
+
+When using GCC, that entry specifies that MakeMaker should first look
+for C (followed by C) in all the locations specified by
+C<$Config{libpth}>.
+
+When using a compiler other than GCC, the above entry will search for
+C (followed by C).
+
+If the library happens to be in a location not in C<$Config{libpth}>,
+you need:
+
+ LIBS => ['-Lc:\gllibs -lgl']
+
+Here is a less often used example:
+
+ LIBS => ['-lgl', ':nosearch -Ld:\mesalibs -lmesa -luser32']
+
+This specifies a search for library C as before. If that search
+fails to find the library, it looks at the next item in the list. The
+C<:nosearch> flag will prevent searching for the libraries that follow,
+so it simply returns the value as C<-Ld:\mesalibs -lmesa -luser32>,
+since GCC can use that value as is with its linker.
+
+When using the Visual C compiler, the second item is returned as
+C<-libpath:d:\mesalibs mesa.lib user32.lib>.
+
+When using the Borland compiler, the second item is returned as
+C<-Ld:\mesalibs mesa.lib user32.lib>, and MakeMaker takes care of
+moving the C<-Ld:\mesalibs> to the correct place in the linker
+command line.
+
+=back
+
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
diff --git a/src/main/perl/lib/ExtUtils/Liblist/Kid.pm b/src/main/perl/lib/ExtUtils/Liblist/Kid.pm
new file mode 100644
index 000000000..2e7210fb1
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/Liblist/Kid.pm
@@ -0,0 +1,646 @@
+package ExtUtils::Liblist::Kid;
+
+# XXX Splitting this out into its own .pm is a temporary solution.
+
+# This kid package is to be used by MakeMaker. It will not work if
+# $self is not a Makemaker.
+
+use 5.006;
+
+# Broken out of MakeMaker from version 4.11
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+use ExtUtils::MakeMaker::Config;
+use Cwd 'cwd';
+use File::Basename;
+use File::Spec;
+
+sub ext {
+ if ( $^O eq 'VMS' ) { goto &_vms_ext; }
+ elsif ( $^O eq 'MSWin32' ) { goto &_win32_ext; }
+ else { goto &_unix_os2_ext; }
+}
+
+sub _space_dirs_split {
+ my ($libpth) = @_;
+ return if !length $libpth;
+ my (@chunks, @ret);
+ push @chunks, [$1,$2] while $libpth =~ /(\S+)(\s*)/g;
+ CHUNK: while (@chunks) {
+ my ($c, $ind) = (shift(@chunks), 0);
+ if (-d $c->[0]) { push @ret, $c->[0]; next CHUNK; }
+ my $sofar = join '', @$c;
+ while ($ind < @chunks) {
+ my ($this_word, $this_space) = @{ $chunks[$ind] };
+ $sofar .= $this_word;
+ if (-d $sofar) { push @ret, $sofar; next CHUNK; }
+ $sofar .= $this_space;
+ $ind++;
+ }
+ }
+ @ret;
+}
+
+sub _unix_os2_ext {
+ my ( $self, $potential_libs, $verbose, $give_libs ) = @_;
+ $verbose ||= 0;
+
+ if ( $^O =~ /os2|android/ and $Config{perllibs} ) {
+
+ # Dynamic libraries are not transitive, so we may need including
+ # the libraries linked against perl.dll/libperl.so again.
+
+ $potential_libs .= " " if $potential_libs;
+ $potential_libs .= $Config{perllibs};
+ }
+ return ( "", "", "", "", ( $give_libs ? [] : () ) ) unless $potential_libs;
+ warn "Potential libraries are '$potential_libs':\n" if $verbose;
+
+ my ( $so ) = $Config{so};
+ my ( $libs ) = defined $Config{perllibs} ? $Config{perllibs} : $Config{libs};
+ my $Config_libext = $Config{lib_ext} || ".a";
+ my $Config_dlext = $Config{dlext};
+
+ # compute $extralibs, $bsloadlibs and $ldloadlibs from
+ # $potential_libs
+ # this is a rewrite of Andy Dougherty's extliblist in perl
+
+ require Text::ParseWords;
+
+ my @searchpath; # from "-L/path" entries in $potential_libs
+ my @libpath = _space_dirs_split($Config{libpth} || '');
+ my ( @ldloadlibs, @bsloadlibs, @extralibs, @ld_run_path, %ld_run_path_seen );
+ my ( @libs, %libs_seen );
+ my ( $fullname, @fullname );
+ my ( $pwd ) = cwd(); # from Cwd.pm
+ my ( $found ) = 0;
+ if ($Config{gccversion}) {
+ chomp(my @incpath = grep s/^ //, grep { /^#include .. /^End of search / } `$Config{cc} -E -v - &1 >/dev/null`);
+ unshift @libpath, map { s{/include[^/]*}{/lib}; $_ } @incpath
+ }
+ @libpath = grep -d, @libpath;
+
+ if ($^O eq 'darwin') {
+ # 'escape' Mach-O ld -framework and -F flags, so they aren't dropped later on
+ $found++ if $potential_libs =~ s/(^|\s)(-(?:weak_|reexport_|lazy_)?framework)\s+(\S+)/$1-Wl,$2 -Wl,$3/g;
+ $found++ if $potential_libs =~ s/(^|\s)(-F)\s*(\S+)/$1-Wl,$2 -Wl,$3/g;
+ }
+
+ foreach my $thislib ( Text::ParseWords::shellwords($potential_libs) ) {
+ my ( $custom_name ) = '';
+
+ # Handle possible linker path arguments.
+ if ( $thislib =~ s/^(-[LR]|-Wl,-R|-Wl,-rpath,)// ) { # save path flag type
+ my ( $ptype ) = $1;
+ unless ( -d $thislib ) {
+ warn "$ptype$thislib ignored, directory does not exist\n"
+ if $verbose;
+ next;
+ }
+ my ( $rtype ) = $ptype;
+ if ( ( $ptype eq '-R' ) or ( $ptype =~ m!^-Wl,-[Rr]! ) ) {
+ if ( $Config{'lddlflags'} =~ /-Wl,-[Rr]/ ) {
+ $rtype = '-Wl,-R';
+ }
+ elsif ( $Config{'lddlflags'} =~ /-R/ ) {
+ $rtype = '-R';
+ }
+ }
+ unless ( File::Spec->file_name_is_absolute( $thislib ) ) {
+ warn "Warning: $ptype$thislib changed to $ptype$pwd/$thislib\n";
+ $thislib = $self->catdir( $pwd, $thislib );
+ }
+ push( @searchpath, $thislib );
+ $thislib = qq{"$thislib"} if $thislib =~ / /; # protect spaces if there
+ push( @extralibs, "$ptype$thislib" );
+ push( @ldloadlibs, "$rtype$thislib" );
+ next;
+ }
+
+ if ( $thislib =~ m!^-Wl,! ) {
+ push( @extralibs, $thislib );
+ push( @ldloadlibs, $thislib );
+ next;
+ }
+
+ # Handle possible library arguments.
+ if ( $thislib =~ s/^-l(:)?// ) {
+ # Handle -l:foo.so, which means that the library will
+ # actually be called foo.so, not libfoo.so. This
+ # is used in Android by ExtUtils::Depends to allow one XS
+ # module to link to another.
+ $custom_name = $1 || '';
+ }
+ else {
+ warn "Unrecognized argument in LIBS ignored: '$thislib'\n";
+ next;
+ }
+
+ my ( $found_lib ) = 0;
+ foreach my $thispth ( @searchpath, @libpath ) {
+
+ # Try to find the full name of the library. We need this to
+ # determine whether it's a dynamically-loadable library or not.
+ # This tends to be subject to various os-specific quirks.
+ # For gcc-2.6.2 on linux (March 1995), DLD can not load
+ # .sa libraries, with the exception of libm.sa, so we
+ # deliberately skip them.
+ if ((@fullname =
+ $self->lsdir($thispth, "^\Qlib$thislib.$so.\E[0-9]+")) ||
+ (@fullname =
+ $self->lsdir($thispth, "^\Qlib$thislib.\E[0-9]+\Q\.$so"))) {
+ # Take care that libfoo.so.10 wins against libfoo.so.9.
+ # Compare two libraries to find the most recent version
+ # number. E.g. if you have libfoo.so.9.0.7 and
+ # libfoo.so.10.1, first convert all digits into two
+ # decimal places. Then we'll add ".00" to the shorter
+ # strings so that we're comparing strings of equal length
+ # Thus we'll compare libfoo.so.09.07.00 with
+ # libfoo.so.10.01.00. Some libraries might have letters
+ # in the version. We don't know what they mean, but will
+ # try to skip them gracefully -- we'll set any letter to
+ # '0'. Finally, sort in reverse so we can take the
+ # first element.
+
+ #TODO: iterate through the directory instead of sorting
+
+ $fullname = "$thispth/" . (
+ sort {
+ my ( $ma ) = $a;
+ my ( $mb ) = $b;
+ $ma =~ tr/A-Za-z/0/s;
+ $ma =~ s/\b(\d)\b/0$1/g;
+ $mb =~ tr/A-Za-z/0/s;
+ $mb =~ s/\b(\d)\b/0$1/g;
+ while ( length( $ma ) < length( $mb ) ) { $ma .= ".00"; }
+ while ( length( $mb ) < length( $ma ) ) { $mb .= ".00"; }
+
+ # Comparison deliberately backwards
+ $mb cmp $ma;
+ } @fullname
+ )[0];
+ }
+ elsif ( -f ( $fullname = "$thispth/lib$thislib.$so" ) )
+ {
+ }
+ elsif (-f ( $fullname = "$thispth/lib${thislib}_s$Config_libext" )
+ && ( $Config{'archname'} !~ /RM\d\d\d-svr4/ )
+ && ( $thislib .= "_s" ) )
+ { # we must explicitly use _s version
+ }
+ elsif ( -f ( $fullname = "$thispth/lib$thislib$Config_libext" ) ) {
+ }
+ elsif ( defined( $Config_dlext )
+ && -f ( $fullname = "$thispth/lib$thislib.$Config_dlext" ) )
+ {
+ }
+ elsif ( $^O eq 'darwin' && require DynaLoader && defined &DynaLoader::dl_load_file
+ && DynaLoader::dl_load_file( $fullname = "$thispth/lib$thislib.$so", 0 ) )
+ {
+ }
+ elsif ( -f ( $fullname = "$thispth/$thislib$Config_libext" ) ) {
+ }
+ elsif ( -f ( $fullname = "$thispth/lib$thislib.dll$Config_libext" ) ) {
+ }
+ elsif ( $^O eq 'cygwin' && -f ( $fullname = "$thispth/$thislib.dll" ) ) {
+ }
+ elsif ( -f ( $fullname = "$thispth/Slib$thislib$Config_libext" ) ) {
+ }
+ elsif ($^O eq 'dgux'
+ && -l ( $fullname = "$thispth/lib$thislib$Config_libext" )
+ && readlink( $fullname ) =~ /^elink:/s )
+ {
+
+ # Some of DG's libraries look like misconnected symbolic
+ # links, but development tools can follow them. (They
+ # look like this:
+ #
+ # libm.a -> elink:${SDE_PATH:-/usr}/sde/\
+ # ${TARGET_BINARY_INTERFACE:-m88kdgux}/usr/lib/libm.a
+ #
+ # , the compilation tools expand the environment variables.)
+ }
+ elsif ( $custom_name && -f ( $fullname = "$thispth/$thislib" ) ) {
+ }
+ else {
+ warn "$thislib not found in $thispth\n" if $verbose;
+ next;
+ }
+ warn "'-l$thislib' found at $fullname\n" if $verbose;
+ push @libs, $fullname unless $libs_seen{$fullname}++;
+ $found++;
+ $found_lib++;
+
+ # Now update library lists
+
+ # what do we know about this library...
+ # "Sounds like we should always assume it's a dynamic library on AIX."
+ my $is_dyna = $^O eq 'aix' ? 1 : ( $fullname !~ /\Q$Config_libext\E\z/ );
+ my $in_perl = ( $libs =~ /\B-l:?\Q${thislib}\E\b/s );
+
+ # include the path to the lib once in the dynamic linker path
+ # but only if it is a dynamic lib and not in Perl itself
+ my ( $fullnamedir ) = dirname( $fullname );
+ push @ld_run_path, $fullnamedir
+ if $is_dyna
+ && !$in_perl
+ && !$ld_run_path_seen{$fullnamedir}++;
+
+ # Do not add it into the list if it is already linked in
+ # with the main perl executable.
+ push( @extralibs, "-l$custom_name$thislib" )
+ unless $in_perl;
+
+ if ( $is_dyna ) {
+
+ # For SunOS4, do not add in this shared library if
+ # it is already linked in the main perl executable
+ push( @ldloadlibs, "-l$custom_name$thislib" )
+ unless ( $in_perl and $^O eq 'sunos' );
+ }
+ else {
+ push( @ldloadlibs, "-l$custom_name$thislib" );
+ }
+ last; # found one here so don't bother looking further
+ }
+ warn "Warning (mostly harmless): " . "No library found for -l$thislib\n"
+ unless $found_lib > 0;
+ }
+
+ return ( '', '', '', '', ( $give_libs ? \@libs : () ) ) unless $found;
+ ( "@extralibs", "@bsloadlibs", "@ldloadlibs", join( ":", @ld_run_path ), ( $give_libs ? \@libs : () ) );
+}
+
+sub _win32_ext {
+
+ require Text::ParseWords;
+
+ my ( $self, $potential_libs, $verbose, $give_libs ) = @_;
+ $verbose ||= 0;
+
+ # If user did not supply a list, we punt.
+ # (caller should probably use the list in $Config{libs})
+ return ( "", "", "", "", ( $give_libs ? [] : () ) ) unless $potential_libs;
+
+ # TODO: make this use MM_Win32.pm's compiler detection
+ my %libs_seen;
+ my @extralibs;
+ my $cc = $Config{cc} || '';
+ my $VC = $cc =~ /\bcl\b/i;
+ my $GC = $cc =~ /\bgcc\b/i;
+
+ my $libext = _win32_lib_extensions();
+ my @searchpath = ( '' ); # from "-L/path" entries in $potential_libs
+ my @libpath = _win32_default_search_paths( $VC, $GC );
+ my $pwd = cwd(); # from Cwd.pm
+ my $search = 1;
+
+ # compute @extralibs from $potential_libs
+ my @lib_search_list = _win32_make_lib_search_list( $potential_libs, $verbose );
+ for ( @lib_search_list ) {
+
+ my $thislib = $_;
+
+ # see if entry is a flag
+ if ( /^:\w+$/ ) {
+ $search = 0 if lc eq ':nosearch';
+ $search = 1 if lc eq ':search';
+ _debug( "Ignoring unknown flag '$thislib'\n", $verbose ) if !/^:(no)?(search|default)$/i;
+ next;
+ }
+
+ # if searching is disabled, do compiler-specific translations
+ unless ( $search ) {
+ s/^-l(.+)$/$1.lib/ unless $GC;
+ s/^-L/-libpath:/ if $VC;
+ push( @extralibs, $_ );
+ next;
+ }
+
+ # handle possible linker path arguments
+ if ( s/^-L// and not -d ) {
+ _debug( "$thislib ignored, directory does not exist\n", $verbose );
+ next;
+ }
+ elsif ( -d ) {
+ unless ( File::Spec->file_name_is_absolute( $_ ) ) {
+ warn "Warning: '$thislib' changed to '-L$pwd/$_'\n";
+ $_ = $self->catdir( $pwd, $_ );
+ }
+ push( @searchpath, $_ );
+ next;
+ }
+
+ my @paths = ( @searchpath, @libpath );
+ my ( $fullname, $path ) = _win32_search_file( $thislib, $libext, \@paths, $verbose, $GC );
+
+ if ( !$fullname ) {
+ warn "Warning (mostly harmless): No library found for $thislib\n";
+ next;
+ }
+
+ _debug( "'$thislib' found as '$fullname'\n", $verbose );
+ push( @extralibs, $fullname );
+ $libs_seen{$fullname} = 1 if $path; # why is this a special case?
+ }
+
+ my @libs = sort keys %libs_seen;
+
+ return ( '', '', '', '', ( $give_libs ? \@libs : () ) ) unless @extralibs;
+
+ # make sure paths with spaces are properly quoted
+ @extralibs = map { qq["$_"] } @extralibs;
+ @libs = map { qq["$_"] } @libs;
+
+ my $lib = join( ' ', @extralibs );
+
+ # normalize back to backward slashes (to help braindead tools)
+ # XXX this may break equally braindead GNU tools that don't understand
+ # backslashes, either. Seems like one can't win here. Cursed be CP/M.
+ $lib =~ s,/,\\,g;
+
+ _debug( "Result: $lib\n", $verbose );
+ wantarray ? ( $lib, '', $lib, '', ( $give_libs ? \@libs : () ) ) : $lib;
+}
+
+sub _win32_make_lib_search_list {
+ my ( $potential_libs, $verbose ) = @_;
+ _debug( "Potential libraries are '$potential_libs':\n", $verbose );
+ $potential_libs =~ s,\\,/,g; # normalize to forward slashes
+ Text::ParseWords::quotewords( '\s+', 0, $potential_libs );
+}
+
+sub _win32_default_search_paths {
+ my ( $VC, $GC ) = @_;
+
+ my $libpth = $Config{'libpth'} || '';
+ $libpth =~ s,\\,/,g; # normalize to forward slashes
+
+ my @libpath = _space_dirs_split($libpth);
+ push @libpath, "$Config{installarchlib}/CORE"; # add "$Config{installarchlib}/CORE" to default search path
+
+ push @libpath, split /;/, $ENV{LIB} if $VC and $ENV{LIB};
+ push @libpath, split /;/, $ENV{LIBRARY_PATH} if $GC and $ENV{LIBRARY_PATH};
+ push @libpath, "$ENV{SYSTEMROOT}\\system32" if $ENV{SYSTEMROOT};
+
+ return @libpath;
+}
+
+sub _win32_search_file {
+ my ( $thislib, $libext, $paths, $verbose, $GC ) = @_;
+
+ my @file_list = _win32_build_file_list( $thislib, $GC, $libext );
+
+ for my $lib_file ( @file_list ) {
+ for my $path ( @{$paths} ) {
+ my $fullname = $lib_file;
+ $fullname = "$path\\$fullname" if $path;
+
+ return ( $fullname, $path ) if -f $fullname;
+
+ _debug( "'$thislib' not found as '$fullname'\n", $verbose );
+ }
+ }
+
+ return;
+}
+
+sub _win32_build_file_list {
+ my ( $lib, $GC, $extensions ) = @_;
+
+ my @pre_fixed = _win32_build_prefixed_list( $lib, $GC );
+ return map _win32_attach_extensions( $_, $extensions ), @pre_fixed;
+}
+
+sub _win32_build_prefixed_list {
+ my ( $lib, $GC ) = @_;
+
+ return $lib if $lib !~ s/^-l//;
+ return $lib if $lib =~ /^lib/ and !$GC;
+
+ ( my $no_prefix = $lib ) =~ s/^lib//i;
+ $lib = "lib$lib" if $no_prefix eq $lib;
+
+ return ( $lib, $no_prefix ) if $GC;
+ return ( $no_prefix, $lib );
+}
+
+sub _win32_attach_extensions {
+ my ( $lib, $extensions ) = @_;
+ return map _win32_try_attach_extension( $lib, $_ ), @{$extensions};
+}
+
+sub _win32_try_attach_extension {
+ my ( $lib, $extension ) = @_;
+
+ return $lib if $lib =~ /\Q$extension\E$/i;
+ return "$lib$extension";
+}
+
+sub _win32_lib_extensions {
+ my @extensions = grep $_, @Config{qw(lib_ext)};
+ push @extensions, map ".$_", grep $_, @Config{qw(dlext so)};
+ push @extensions, '.dll.a' if grep { m!^\.a$! } @extensions;
+ push @extensions, '.lib' unless grep { m!^\.lib$! } @extensions;
+ return \@extensions;
+}
+
+sub _debug {
+ my ( $message, $verbose ) = @_;
+ return if !$verbose;
+ warn $message;
+ return;
+}
+
+sub _vms_ext {
+ my ( $self, $potential_libs, $verbose, $give_libs ) = @_;
+ $verbose ||= 0;
+
+ my ( @crtls, $crtlstr );
+ @crtls = ( ( $Config{'ldflags'} =~ m-/Debug-i ? $Config{'dbgprefix'} : '' ) . 'PerlShr/Share' );
+ push( @crtls, grep { not /\(/ } split /\s+/, $Config{'perllibs'} );
+ push( @crtls, grep { not /\(/ } split /\s+/, $Config{'libc'} );
+
+ # In general, we pass through the basic libraries from %Config unchanged.
+ # The one exception is that if we're building in the Perl source tree, and
+ # a library spec could be resolved via a logical name, we go to some trouble
+ # to insure that the copy in the local tree is used, rather than one to
+ # which a system-wide logical may point.
+ if ( $self->{PERL_SRC} ) {
+ my ( $locspec, $type );
+ foreach my $lib ( @crtls ) {
+ if ( ( $locspec, $type ) = $lib =~ m{^([\w\$-]+)(/\w+)?} and $locspec =~ /perl/i ) {
+ if ( lc $type eq '/share' ) { $locspec .= $Config{'exe_ext'}; }
+ elsif ( lc $type eq '/library' ) { $locspec .= $Config{'lib_ext'}; }
+ else { $locspec .= $Config{'obj_ext'}; }
+ $locspec = $self->catfile( $self->{PERL_SRC}, $locspec );
+ $lib = "$locspec$type" if -e $locspec;
+ }
+ }
+ }
+ $crtlstr = @crtls ? join( ' ', @crtls ) : '';
+
+ unless ( $potential_libs ) {
+ warn "Result:\n\tEXTRALIBS: \n\tLDLOADLIBS: $crtlstr\n" if $verbose;
+ return ( '', '', $crtlstr, '', ( $give_libs ? [] : () ) );
+ }
+
+ my ( %found, @fndlibs, $ldlib );
+ my $cwd = cwd();
+ my ( $so, $lib_ext, $obj_ext ) = @Config{ 'so', 'lib_ext', 'obj_ext' };
+
+ # List of common Unix library names and their VMS equivalents
+ # (VMS equivalent of '' indicates that the library is automatically
+ # searched by the linker, and should be skipped here.)
+ my ( @flibs, %libs_seen );
+ my %libmap = (
+ 'm' => '',
+ 'f77' => '',
+ 'F77' => '',
+ 'V77' => '',
+ 'c' => '',
+ 'malloc' => '',
+ 'crypt' => '',
+ 'resolv' => '',
+ 'c_s' => '',
+ 'socket' => '',
+ 'X11' => 'DECW$XLIBSHR',
+ 'Xt' => 'DECW$XTSHR',
+ 'Xm' => 'DECW$XMLIBSHR',
+ 'Xmu' => 'DECW$XMULIBSHR'
+ );
+
+ warn "Potential libraries are '$potential_libs'\n" if $verbose;
+
+ # First, sort out directories and library names in the input
+ my ( @dirs, @libs );
+ foreach my $lib ( split ' ', $potential_libs ) {
+ push( @dirs, $1 ), next if $lib =~ /^-L(.*)/;
+ push( @dirs, $lib ), next if $lib =~ /[:>\]]$/;
+ push( @dirs, $lib ), next if -d $lib;
+ push( @libs, $1 ), next if $lib =~ /^-l(.*)/;
+ push( @libs, $lib );
+ }
+ push( @dirs, split( ' ', $Config{'libpth'} ) );
+
+ # Now make sure we've got VMS-syntax absolute directory specs
+ # (We don't, however, check whether someone's hidden a relative
+ # path in a logical name.)
+ foreach my $dir ( @dirs ) {
+ unless ( -d $dir ) {
+ warn "Skipping nonexistent Directory $dir\n" if $verbose > 1;
+ $dir = '';
+ next;
+ }
+ warn "Resolving directory $dir\n" if $verbose;
+ if ( File::Spec->file_name_is_absolute( $dir ) ) {
+ $dir = VMS::Filespec::vmspath( $dir );
+ }
+ else {
+ $dir = $self->catdir( $cwd, $dir );
+ }
+ }
+ @dirs = grep { length( $_ ) } @dirs;
+ unshift( @dirs, '' ); # Check each $lib without additions first
+
+ LIB: foreach my $lib ( @libs ) {
+ if ( exists $libmap{$lib} ) {
+ next unless length $libmap{$lib};
+ $lib = $libmap{$lib};
+ }
+
+ my ( @variants, $cand );
+ my ( $ctype ) = '';
+
+ # If we don't have a file type, consider it a possibly abbreviated name and
+ # check for common variants. We try these first to grab libraries before
+ # a like-named executable image (e.g. -lperl resolves to perlshr.exe
+ # before perl.exe).
+ if ( $lib !~ /\.[^:>\]]*$/ ) {
+ push( @variants, "${lib}shr", "${lib}rtl", "${lib}lib" );
+ push( @variants, "lib$lib" ) if $lib !~ /[:>\]]/;
+ }
+ push( @variants, $lib );
+ warn "Looking for $lib\n" if $verbose;
+ foreach my $variant ( @variants ) {
+ my ( $fullname, $name );
+
+ foreach my $dir ( @dirs ) {
+ my ( $type );
+
+ $name = "$dir$variant";
+ warn "\tChecking $name\n" if $verbose > 2;
+ $fullname = VMS::Filespec::rmsexpand( $name );
+ if ( defined $fullname and -f $fullname ) {
+
+ # It's got its own suffix, so we'll have to figure out the type
+ if ( $fullname =~ /(?:$so|exe)$/i ) { $type = 'SHR'; }
+ elsif ( $fullname =~ /(?:$lib_ext|olb)$/i ) { $type = 'OLB'; }
+ elsif ( $fullname =~ /(?:$obj_ext|obj)$/i ) {
+ warn "Warning (mostly harmless): " . "Plain object file $fullname found in library list\n";
+ $type = 'OBJ';
+ }
+ else {
+ warn "Warning (mostly harmless): " . "Unknown library type for $fullname; assuming shared\n";
+ $type = 'SHR';
+ }
+ }
+ elsif (-f ( $fullname = VMS::Filespec::rmsexpand( $name, $so ) )
+ or -f ( $fullname = VMS::Filespec::rmsexpand( $name, '.exe' ) ) )
+ {
+ $type = 'SHR';
+ $name = $fullname unless $fullname =~ /exe;?\d*$/i;
+ }
+ elsif (
+ not length( $ctype ) and # If we've got a lib already,
+ # don't bother
+ ( -f ( $fullname = VMS::Filespec::rmsexpand( $name, $lib_ext ) ) or -f ( $fullname = VMS::Filespec::rmsexpand( $name, '.olb' ) ) )
+ )
+ {
+ $type = 'OLB';
+ $name = $fullname unless $fullname =~ /olb;?\d*$/i;
+ }
+ elsif (
+ not length( $ctype ) and # If we've got a lib already,
+ # don't bother
+ ( -f ( $fullname = VMS::Filespec::rmsexpand( $name, $obj_ext ) ) or -f ( $fullname = VMS::Filespec::rmsexpand( $name, '.obj' ) ) )
+ )
+ {
+ warn "Warning (mostly harmless): " . "Plain object file $fullname found in library list\n";
+ $type = 'OBJ';
+ $name = $fullname unless $fullname =~ /obj;?\d*$/i;
+ }
+ if ( defined $type ) {
+ $ctype = $type;
+ $cand = $name;
+ last if $ctype eq 'SHR';
+ }
+ }
+ if ( $ctype ) {
+
+ push @{ $found{$ctype} }, $cand;
+ warn "\tFound as $cand (really $fullname), type $ctype\n"
+ if $verbose > 1;
+ push @flibs, $name unless $libs_seen{$fullname}++;
+ next LIB;
+ }
+ }
+ warn "Warning (mostly harmless): " . "No library found for $lib\n";
+ }
+
+ push @fndlibs, @{ $found{OBJ} } if exists $found{OBJ};
+ push @fndlibs, map { "$_/Library" } @{ $found{OLB} } if exists $found{OLB};
+ push @fndlibs, map { "$_/Share" } @{ $found{SHR} } if exists $found{SHR};
+ my $lib = join( ' ', @fndlibs );
+
+ $ldlib = $crtlstr ? "$lib $crtlstr" : $lib;
+ $ldlib =~ s/^\s+|\s+$//g;
+ warn "Result:\n\tEXTRALIBS: $lib\n\tLDLOADLIBS: $ldlib\n" if $verbose;
+ wantarray ? ( $lib, '', $ldlib, '', ( $give_libs ? \@flibs : () ) ) : $lib;
+}
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM.pm b/src/main/perl/lib/ExtUtils/MM.pm
index 95f6cf04a..6c3416754 100644
--- a/src/main/perl/lib/ExtUtils/MM.pm
+++ b/src/main/perl/lib/ExtUtils/MM.pm
@@ -2,7 +2,7 @@ package ExtUtils::MM;
use strict;
use warnings;
-our $VERSION = '7.70_perlonjava';
+our $VERSION = '7.78_perlonjava';
our @ISA;
# MM is a compatibility shim that some modules expect.
diff --git a/src/main/perl/lib/ExtUtils/MM_AIX.pm b/src/main/perl/lib/ExtUtils/MM_AIX.pm
new file mode 100644
index 000000000..f7ce23af6
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_AIX.pm
@@ -0,0 +1,80 @@
+package ExtUtils::MM_AIX;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+use ExtUtils::MakeMaker::Config;
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Unix);
+
+=head1 NAME
+
+ExtUtils::MM_AIX - AIX specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality for
+AIX.
+
+Unless otherwise stated it works just like ExtUtils::MM_Unix.
+
+=head2 Overridden methods
+
+=head3 dlsyms
+
+Define DL_FUNCS and DL_VARS and write the *.exp files.
+
+=cut
+
+sub dlsyms {
+ my($self,%attribs) = @_;
+ return '' unless $self->needs_linking;
+ join "\n", $self->xs_dlsyms_iterator(\%attribs);
+}
+
+=head3 xs_dlsyms_ext
+
+On AIX, is C<.exp>.
+
+=cut
+
+sub xs_dlsyms_ext {
+ '.exp';
+}
+
+sub xs_dlsyms_arg {
+ my($self, $file) = @_;
+ my $arg = qq{-bE:${file}};
+ $arg = '-Wl,'.$arg if $Config{lddlflags} =~ /-Wl,-bE:/;
+ return $arg;
+}
+
+sub init_others {
+ my $self = shift;
+ $self->SUPER::init_others;
+ # perl "hints" add -bE:$(BASEEXT).exp to LDDLFLAGS. strip that out
+ # so right value can be added by xs_make_dynamic_lib to work for XSMULTI
+ $self->{LDDLFLAGS} ||= $Config{lddlflags};
+ $self->{LDDLFLAGS} =~ s#(\s*)\S*\Q$(BASEEXT)\E\S*(\s*)#$1$2#;
+ return;
+}
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_Any.pm b/src/main/perl/lib/ExtUtils/MM_Any.pm
new file mode 100644
index 000000000..81633f185
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_Any.pm
@@ -0,0 +1,3112 @@
+package ExtUtils::MM_Any;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+use Carp;
+use File::Spec;
+use File::Basename;
+BEGIN { our @ISA = qw(File::Spec); }
+
+# We need $Verbose
+use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
+
+use ExtUtils::MakeMaker::Config;
+
+
+# So we don't have to keep calling the methods over and over again,
+# we have these globals to cache the values. Faster and shrtr.
+my $Curdir = __PACKAGE__->curdir;
+#my $Updir = __PACKAGE__->updir;
+
+my $METASPEC_URL = 'https://metacpan.org/pod/CPAN::Meta::Spec';
+my $METASPEC_V = 2;
+
+=head1 NAME
+
+ExtUtils::MM_Any - Platform-agnostic MM methods
+
+=head1 SYNOPSIS
+
+ FOR INTERNAL USE ONLY!
+
+ package ExtUtils::MM_SomeOS;
+
+ # Temporarily, you have to subclass both. Put MM_Any first.
+ require ExtUtils::MM_Any;
+ require ExtUtils::MM_Unix;
+ @ISA = qw(ExtUtils::MM_Any ExtUtils::Unix);
+
+=head1 DESCRIPTION
+
+B
+
+ExtUtils::MM_Any is a superclass for the ExtUtils::MM_* set of
+modules. It contains methods which are either inherently
+cross-platform or are written in a cross-platform manner.
+
+Subclass off of ExtUtils::MM_Any I L. This is a
+temporary solution.
+
+B
+
+
+=head1 METHODS
+
+Any methods marked I must be implemented by subclasses.
+
+
+=head2 Cross-platform helper methods
+
+These are methods which help writing cross-platform code.
+
+
+
+=head3 os_flavor I
+
+ my @os_flavor = $mm->os_flavor;
+
+@os_flavor is the style of operating system this is, usually
+corresponding to the MM_*.pm file we're using.
+
+The first element of @os_flavor is the major family (ie. Unix,
+Windows, VMS, OS/2, etc...) and the rest are sub families.
+
+Some examples:
+
+ Cygwin98 ('Unix', 'Cygwin', 'Cygwin9x')
+ Windows ('Win32')
+ Win98 ('Win32', 'Win9x')
+ Linux ('Unix', 'Linux')
+ MacOS X ('Unix', 'Darwin', 'MacOS', 'MacOS X')
+ OS/2 ('OS/2')
+
+This is used to write code for styles of operating system.
+See os_flavor_is() for use.
+
+
+=head3 os_flavor_is
+
+ my $is_this_flavor = $mm->os_flavor_is($this_flavor);
+ my $is_this_flavor = $mm->os_flavor_is(@one_of_these_flavors);
+
+Checks to see if the current operating system is one of the given flavors.
+
+This is useful for code like:
+
+ if( $mm->os_flavor_is('Unix') ) {
+ $out = `foo 2>&1`;
+ }
+ else {
+ $out = `foo`;
+ }
+
+=cut
+
+sub os_flavor_is {
+ my $self = shift;
+ my %flavors = map { ($_ => 1) } $self->os_flavor;
+ return (grep { $flavors{$_} } @_) ? 1 : 0;
+}
+
+
+=head3 can_load_xs
+
+ my $can_load_xs = $self->can_load_xs;
+
+Returns true if we have the ability to load XS.
+
+This is important because miniperl, used to build XS modules in the
+core, can not load XS.
+
+=cut
+
+sub can_load_xs {
+ return defined &DynaLoader::boot_DynaLoader ? 1 : 0;
+}
+
+
+=head3 can_run
+
+ use ExtUtils::MM;
+ my $runnable = MM->can_run($Config{make});
+
+If called in a scalar context it will return the full path to the binary
+you asked for if it was found, or C if it was not.
+
+If called in a list context, it will return a list of the full paths to instances
+of the binary where found in C, or an empty list if it was not found.
+
+Copied from L, but modified into
+a method (and removed C<$INSTANCES> capability).
+
+=cut
+
+sub can_run {
+ my ($self, $command) = @_;
+
+ # a lot of VMS executables have a symbol defined
+ # check those first
+ if ( $^O eq 'VMS' ) {
+ require VMS::DCLsym;
+ my $syms = VMS::DCLsym->new;
+ return $command if scalar $syms->getsym( uc $command );
+ }
+
+ my @possibles;
+
+ if( File::Spec->file_name_is_absolute($command) ) {
+ return $self->maybe_command($command);
+
+ } else {
+ for my $dir (
+ File::Spec->path,
+ File::Spec->curdir
+ ) {
+ next if ! $dir || ! -d $dir;
+ my $abs = File::Spec->catfile($self->os_flavor_is('Win32') ? Win32::GetShortPathName( $dir ) : $dir, $command);
+ push @possibles, $abs if $abs = $self->maybe_command($abs);
+ }
+ }
+ return @possibles if wantarray;
+ return shift @possibles;
+}
+
+
+=head3 can_redirect_error
+
+ $useredirect = MM->can_redirect_error;
+
+True if on an OS where qx operator (or backticks) can redirect C
+onto C.
+
+=cut
+
+sub can_redirect_error {
+ my $self = shift;
+ $self->os_flavor_is('Unix')
+ or ($self->os_flavor_is('Win32') and !$self->os_flavor_is('Win9x'))
+ or $self->os_flavor_is('OS/2')
+}
+
+
+=head3 is_make_type
+
+ my $is_dmake = $self->is_make_type('dmake');
+
+Returns true if C<< $self->make >> is the given type; possibilities are:
+
+ gmake GNU make
+ dmake
+ nmake
+ bsdmake BSD pmake-derived
+
+=cut
+
+my %maketype2true;
+# undocumented - so t/cd.t can still do its thing
+sub _clear_maketype_cache { %maketype2true = () }
+
+sub is_make_type {
+ my($self, $type) = @_;
+ return $maketype2true{$type} if defined $maketype2true{$type};
+ (undef, undef, my $make_basename) = $self->splitpath($self->make);
+ return $maketype2true{$type} = 1
+ if $make_basename =~ /\b$type\b/i; # executable's filename
+ return $maketype2true{$type} = 0
+ if $make_basename =~ /\b[gdn]make\b/i; # Never fall through for dmake/nmake/gmake
+ # now have to run with "-v" and guess
+ my $redirect = $self->can_redirect_error ? '2>&1' : '';
+ my $make = $self->make || $self->{MAKE};
+ my $minus_v = `"$make" -v $redirect`;
+ return $maketype2true{$type} = 1
+ if $type eq 'gmake' and $minus_v =~ /GNU make/i;
+ return $maketype2true{$type} = 1
+ if $type eq 'bsdmake'
+ and $minus_v =~ /^usage:.*make\s*\[-B/im;
+ $maketype2true{$type} = 0; # it wasn't whatever you asked
+}
+
+
+=head3 can_dep_space
+
+ my $can_dep_space = $self->can_dep_space;
+
+Returns true if C can handle (probably by quoting)
+dependencies that contain a space. Currently known true for GNU make,
+false for BSD pmake derivative.
+
+=cut
+
+my $cached_dep_space;
+sub can_dep_space {
+ my $self = shift;
+ return $cached_dep_space if defined $cached_dep_space;
+ return $cached_dep_space = 1 if $self->is_make_type('gmake');
+ return $cached_dep_space = 0 if $self->is_make_type('dmake'); # only on W32
+ return $cached_dep_space = 0 if $self->is_make_type('bsdmake');
+ return $cached_dep_space = 0; # assume no
+}
+
+
+=head3 quote_dep
+
+ $text = $mm->quote_dep($text);
+
+Method that protects Makefile single-value constants (mainly filenames),
+so that make will still treat them as single values even if they
+inconveniently have spaces in. If the make program being used cannot
+achieve such protection and the given text would need it, throws an
+exception.
+
+=cut
+
+sub quote_dep {
+ my ($self, $arg) = @_;
+ die <can_dep_space;
+Tried to use make dependency with space for make that can't:
+ '$arg'
+EOF
+ $arg =~ s/( )/\\$1/g; # how GNU make does it
+ return $arg;
+}
+
+
+=head3 split_command
+
+ my @cmds = $MM->split_command($cmd, @args);
+
+Most OS have a maximum command length they can execute at once. Large
+modules can easily generate commands well past that limit. Its
+necessary to split long commands up into a series of shorter commands.
+
+C will return a series of @cmds each processing part of
+the args. Collectively they will process all the arguments. Each
+individual line in @cmds will not be longer than the
+$self->max_exec_len being careful to take into account macro expansion.
+
+$cmd should include any switches and repeated initial arguments. If it
+has newlines, they should be already escaped.
+
+If no @args are given, no @cmds will be returned.
+
+Pairs of arguments will always be preserved in a single command, this
+is a heuristic for things like pm_to_blib and pod2man which work on
+pairs of arguments. This makes things like this safe:
+
+ $self->split_command($cmd, %pod2man);
+
+
+=cut
+
+sub split_command {
+ my($self, $cmd, @args) = @_;
+
+ my @cmds = ();
+ return(@cmds) unless @args;
+
+ # If the command was given as a here-doc, there's probably a trailing
+ # newline.
+ chomp $cmd;
+
+ # set aside 30% for macro expansion.
+ my $len_left = int($self->max_exec_len * 0.70);
+ $len_left -= length $self->_expand_macros($cmd);
+
+ do {
+ my $arg_str = '';
+ my @next_args;
+ while( @next_args = splice(@args, 0, 2) ) {
+ # Two at a time to preserve pairs.
+ my $next_arg_str = "\t ". join ' ', @next_args, "\n";
+
+ if( !length $arg_str ) {
+ $arg_str .= $next_arg_str
+ }
+ elsif( length($arg_str) + length($next_arg_str) > $len_left ) {
+ unshift @args, @next_args;
+ last;
+ }
+ else {
+ $arg_str .= $next_arg_str;
+ }
+ }
+ chop $arg_str;
+
+ push @cmds, $cmd . $self->escape_newlines(" \n$arg_str");
+ } while @args;
+
+ return @cmds;
+}
+
+
+sub _expand_macros {
+ my($self, $cmd) = @_;
+
+ $cmd =~ s{\$\((\w+)\)}{
+ defined $self->{$1} ? $self->{$1} : "\$($1)"
+ }e;
+ return $cmd;
+}
+
+
+=head3 make_type
+
+Returns a suitable string describing the type of makefile being written.
+
+=cut
+
+# override if this isn't suitable!
+sub make_type { return 'Unix-style'; }
+
+
+=head3 stashmeta
+
+ my @recipelines = $MM->stashmeta($text, $file);
+
+Generates a set of C<@recipelines> which will result in the literal
+C<$text> ending up in literal C<$file> when the recipe is executed. Call
+it once, with all the text you want in C<$file>. Make macros will not
+be expanded, so the locations will be fixed at configure-time, not
+at build-time.
+
+=cut
+
+sub stashmeta {
+ my($self, $text, $file) = @_;
+ $self->echo($text, $file, { allow_variables => 0, append => 0 });
+}
+
+
+=head3 echo
+
+ my @commands = $MM->echo($text);
+ my @commands = $MM->echo($text, $file);
+ my @commands = $MM->echo($text, $file, \%opts);
+
+Generates a set of @commands which print the $text to a $file.
+
+If $file is not given, output goes to STDOUT.
+
+If $opts{append} is true the $file will be appended to rather than
+overwritten. Default is to overwrite.
+
+If $opts{allow_variables} is true, make variables of the form
+C<$(...)> will not be escaped. Other C<$> will. Default is to escape
+all C<$>.
+
+Example of use:
+
+ my $make = join '', map "\t$_\n", $MM->echo($text, $file);
+
+=cut
+
+sub echo {
+ my($self, $text, $file, $opts) = @_;
+
+ # Compatibility with old options
+ if( !ref $opts ) {
+ my $append = $opts;
+ $opts = { append => $append || 0 };
+ }
+ $opts->{allow_variables} = 0 unless defined $opts->{allow_variables};
+
+ my $ql_opts = { allow_variables => $opts->{allow_variables} };
+ my @cmds = map { '$(NOECHO) $(ECHO) '.$self->quote_literal($_, $ql_opts) }
+ split /\n/, $text;
+ if( $file ) {
+ my $redirect = $opts->{append} ? '>>' : '>';
+ $cmds[0] .= " $redirect $file";
+ $_ .= " >> $file" foreach @cmds[1..$#cmds];
+ }
+
+ return @cmds;
+}
+
+
+=head3 wraplist
+
+ my $args = $mm->wraplist(@list);
+
+Takes an array of items and turns them into a well-formatted list of
+arguments. In most cases this is simply something like:
+
+ FOO \
+ BAR \
+ BAZ
+
+=cut
+
+sub wraplist {
+ my $self = shift;
+ return join " \\\n\t", @_;
+}
+
+
+=head3 maketext_filter
+
+ my $filter_make_text = $mm->maketext_filter($make_text);
+
+The text of the Makefile is run through this method before writing to
+disk. It allows systems a chance to make portability fixes to the
+Makefile.
+
+By default it does nothing.
+
+This method is protected and not intended to be called outside of
+MakeMaker.
+
+=cut
+
+sub maketext_filter { return $_[1] }
+
+
+=head3 cd I
+
+ my $subdir_cmd = $MM->cd($subdir, @cmds);
+
+This will generate a make fragment which runs the @cmds in the given
+$dir. The rough equivalent to this, except cross platform.
+
+ cd $subdir && $cmd
+
+Currently $dir can only go down one level. "foo" is fine. "foo/bar" is
+not. "../foo" is right out.
+
+The resulting $subdir_cmd has no leading tab nor trailing newline. This
+makes it easier to embed in a make string. For example.
+
+ my $make = sprintf <<'CODE', $subdir_cmd;
+ foo :
+ $(ECHO) what
+ %s
+ $(ECHO) mouche
+ CODE
+
+
+=head3 oneliner I
+
+ my $oneliner = $MM->oneliner($perl_code);
+ my $oneliner = $MM->oneliner($perl_code, \@switches);
+
+This will generate a perl one-liner safe for the particular platform
+you're on based on the given $perl_code and @switches (a -e is
+assumed) suitable for using in a make target. It will use the proper
+shell quoting and escapes.
+
+$(PERLRUN) will be used as perl.
+
+Any newlines in $perl_code will be escaped. Leading and trailing
+newlines will be stripped. Makes this idiom much easier:
+
+ my $code = $MM->oneliner(<<'CODE', [...switches...]);
+some code here
+another line here
+CODE
+
+Usage might be something like:
+
+ # an echo emulation
+ $oneliner = $MM->oneliner('print "Foo\n"');
+ $make = '$oneliner > somefile';
+
+Dollar signs in the $perl_code will be protected from make using the
+C method, unless they are recognised as being a make
+variable, C<$(varname)>, in which case they will be left for make
+to expand. Remember to quote make macros else it might be used as a
+bareword. For example:
+
+ # Assign the value of the $(VERSION_FROM) make macro to $vf.
+ $oneliner = $MM->oneliner('$vf = "$(VERSION_FROM)"');
+
+It's currently very simple, and may be expanded sometime in the future
+to include more flexible code and switches.
+
+
+=head3 quote_literal I
+
+ my $safe_text = $MM->quote_literal($text);
+ my $safe_text = $MM->quote_literal($text, \%options);
+
+This will quote $text so it is interpreted literally in the shell.
+
+For example, on Unix this would escape any single-quotes in $text and
+put single-quotes around the whole thing.
+
+If $options{allow_variables} is true it will leave C<'$(FOO)'> make
+variables untouched. If false they will be escaped like any other
+C<$>. Defaults to true.
+
+=head3 escape_dollarsigns
+
+ my $escaped_text = $MM->escape_dollarsigns($text);
+
+Escapes stray C<$> so they are not interpreted as make variables.
+
+It lets by C<$(...)>.
+
+=cut
+
+sub escape_dollarsigns {
+ my($self, $text) = @_;
+
+ # Escape dollar signs which are not starting a variable
+ $text =~ s{\$ (?!\() }{\$\$}gx;
+
+ return $text;
+}
+
+
+=head3 escape_all_dollarsigns
+
+ my $escaped_text = $MM->escape_all_dollarsigns($text);
+
+Escapes all C<$> so they are not interpreted as make variables.
+
+=cut
+
+sub escape_all_dollarsigns {
+ my($self, $text) = @_;
+
+ # Escape dollar signs
+ $text =~ s{\$}{\$\$}gx;
+
+ return $text;
+}
+
+
+=head3 escape_newlines I
+
+ my $escaped_text = $MM->escape_newlines($text);
+
+Shell escapes newlines in $text.
+
+
+=head3 max_exec_len I
+
+ my $max_exec_len = $MM->max_exec_len;
+
+Calculates the maximum command size the OS can exec. Effectively,
+this is the max size of a shell command line.
+
+=for _private
+$self->{_MAX_EXEC_LEN} is set by this method, but only for testing purposes.
+
+
+=head3 make
+
+ my $make = $MM->make;
+
+Returns the make variant we're generating the Makefile for. This attempts
+to do some normalization on the information from %Config or the user.
+
+=cut
+
+sub make {
+ my $self = shift;
+
+ my $make = lc $self->{MAKE};
+
+ # Truncate anything like foomake6 to just foomake.
+ $make =~ s/^(\w+make).*/$1/;
+
+ # Turn gnumake into gmake.
+ $make =~ s/^gnu/g/;
+
+ return $make;
+}
+
+
+=head2 Targets
+
+These are methods which produce make targets.
+
+
+=head3 all_target
+
+Generate the default target 'all'.
+
+=cut
+
+sub all_target {
+ my $self = shift;
+
+ return <<'MAKE_EXT';
+all :: pure_all
+ $(NOECHO) $(NOOP)
+MAKE_EXT
+
+}
+
+
+=head3 blibdirs_target
+
+ my $make_frag = $mm->blibdirs_target;
+
+Creates the blibdirs target which creates all the directories we use
+in blib/.
+
+The blibdirs.ts target is deprecated. Depend on blibdirs instead.
+
+
+=cut
+
+sub _xs_list_basenames {
+ my ($self) = @_;
+ map { (my $b = $_) =~ s/\.xs$//; $b } sort keys %{ $self->{XS} };
+}
+
+sub blibdirs_target {
+ my $self = shift;
+
+ my @dirs = map { uc "\$(INST_$_)" } qw(libdir archlib
+ autodir archautodir
+ bin script
+ man1dir man3dir
+ );
+ if ($self->{XSMULTI}) {
+ for my $ext ($self->_xs_list_basenames) {
+ my ($v, $d, $f) = File::Spec->splitpath($ext);
+ my @d = File::Spec->splitdir($d);
+ shift @d if $d[0] eq 'lib';
+ push @dirs, $self->catdir('$(INST_ARCHLIB)', 'auto', @d, $f);
+ }
+ }
+
+ my @exists = map { $_.'$(DFSEP).exists' } @dirs;
+
+ my $make = sprintf <<'MAKE', join(' ', @exists);
+blibdirs : %s
+ $(NOECHO) $(NOOP)
+
+# Backwards compat with 6.18 through 6.25
+blibdirs.ts : blibdirs
+ $(NOECHO) $(NOOP)
+
+MAKE
+
+ $make .= $self->dir_target(@dirs);
+
+ return $make;
+}
+
+
+=head3 clean (o)
+
+Defines the clean target.
+
+=cut
+
+sub clean {
+# --- Cleanup and Distribution Sections ---
+
+ my($self, %attribs) = @_;
+ my @m;
+ push(@m, '
+# Delete temporary files but do not touch installed files. We don\'t delete
+# the Makefile here so a later make realclean still has a makefile to use.
+
+clean :: clean_subdirs
+');
+
+ my @files = sort values %{$self->{XS}}; # .c files from *.xs files
+ push @files, map {
+ my $file = $_;
+ map { $file.$_ } $self->{OBJ_EXT}, qw(.def _def.old .bs .bso .exp .base);
+ } $self->_xs_list_basenames;
+ my @dirs = qw(blib);
+
+ # Normally these are all under blib but they might have been
+ # redefined.
+ # XXX normally this would be a good idea, but the Perl core sets
+ # INST_LIB = ../../lib rather than actually installing the files.
+ # So a "make clean" in an ext/ directory would blow away lib.
+ # Until the core is adjusted let's leave this out.
+# push @dirs, qw($(INST_ARCHLIB) $(INST_LIB)
+# $(INST_BIN) $(INST_SCRIPT)
+# $(INST_MAN1DIR) $(INST_MAN3DIR)
+# $(INST_LIBDIR) $(INST_ARCHLIBDIR) $(INST_AUTODIR)
+# $(INST_STATIC) $(INST_DYNAMIC)
+# );
+
+
+ if( $attribs{FILES} ) {
+ # Use @dirs because we don't know what's in here.
+ push @dirs, ref $attribs{FILES} ?
+ @{$attribs{FILES}} :
+ split /\s+/, $attribs{FILES} ;
+ }
+
+ push(@files, qw[$(MAKE_APERL_FILE)
+ MYMETA.json MYMETA.yml perlmain.c tmon.out mon.out so_locations
+ blibdirs.ts pm_to_blib pm_to_blib.ts
+ *$(OBJ_EXT) *$(LIB_EXT) perl.exe perl perl$(EXE_EXT)
+ $(BOOTSTRAP) $(BASEEXT).bso
+ $(BASEEXT).def lib$(BASEEXT).def
+ $(BASEEXT).exp $(BASEEXT).x
+ ]);
+
+ push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'));
+ push(@files, $self->catfile('$(INST_ARCHAUTODIR)','extralibs.ld'));
+
+ # core files
+ if ($^O eq 'vos') {
+ push(@files, qw[perl*.kp]);
+ }
+ else {
+ push(@files, qw[core core.*perl.*.? *perl.core]);
+ }
+
+ push(@files, map { "core." . "[0-9]"x$_ } (1..5));
+
+ # OS specific things to clean up. Use @dirs since we don't know
+ # what might be in here.
+ push @dirs, $self->extra_clean_files;
+
+ # Occasionally files are repeated several times from different sources
+ { my(%f) = map { ($_ => 1) } @files; @files = sort keys %f; }
+ { my(%d) = map { ($_ => 1) } @dirs; @dirs = sort keys %d; }
+
+ push @m, map "\t$_\n", $self->split_command('- $(RM_F)', @files);
+ push @m, map "\t$_\n", $self->split_command('- $(RM_RF)', @dirs);
+
+ # Leave Makefile.old around for realclean
+ push @m, <<'MAKE';
+ $(NOECHO) $(RM_F) $(MAKEFILE_OLD)
+ - $(MV) $(FIRST_MAKEFILE) $(MAKEFILE_OLD) $(DEV_NULL)
+MAKE
+
+ push(@m, "\t$attribs{POSTOP}\n") if $attribs{POSTOP};
+
+ join("", @m);
+}
+
+
+=head3 clean_subdirs_target
+
+ my $make_frag = $MM->clean_subdirs_target;
+
+Returns the clean_subdirs target. This is used by the clean target to
+call clean on any subdirectories which contain Makefiles.
+
+=cut
+
+sub clean_subdirs_target {
+ my($self) = shift;
+
+ # No subdirectories, no cleaning.
+ return <<'NOOP_FRAG' unless @{$self->{DIR}};
+clean_subdirs :
+ $(NOECHO) $(NOOP)
+NOOP_FRAG
+
+
+ my $clean = "clean_subdirs :\n";
+
+ for my $dir (@{$self->{DIR}}) {
+ my $subclean = $self->oneliner(sprintf <<'CODE', $dir);
+exit 0 unless chdir '%s'; system '$(MAKE) clean' if -f '$(FIRST_MAKEFILE)';
+CODE
+
+ $clean .= "\t$subclean\n";
+ }
+
+ return $clean;
+}
+
+
+=head3 dir_target
+
+ my $make_frag = $mm->dir_target(@directories);
+
+Generates targets to create the specified directories and set its
+permission to PERM_DIR.
+
+Because depending on a directory to just ensure it exists doesn't work
+too well (the modified time changes too often) dir_target() creates a
+.exists file in the created directory. It is this you should depend on.
+For portability purposes you should use the $(DIRFILESEP) macro rather
+than a '/' to separate the directory from the file.
+
+ yourdirectory$(DIRFILESEP).exists
+
+=cut
+
+sub dir_target {
+ my($self, @dirs) = @_;
+
+ my $make = '';
+ foreach my $dir (@dirs) {
+ $make .= sprintf <<'MAKE', ($dir) x 4;
+%s$(DFSEP).exists :: Makefile.PL
+ $(NOECHO) $(MKPATH) %s
+ $(NOECHO) $(CHMOD) $(PERM_DIR) %s
+ $(NOECHO) $(TOUCH) %s$(DFSEP).exists
+
+MAKE
+
+ }
+
+ return $make;
+}
+
+
+=head3 distdir
+
+Defines the scratch directory target that will hold the distribution
+before tar-ing (or shar-ing).
+
+=cut
+
+# For backwards compatibility.
+*dist_dir = *distdir;
+
+sub distdir {
+ my($self) = shift;
+
+ my $meta_target = $self->{NO_META} ? '' : 'distmeta';
+ my $sign_target = !$self->{SIGN} ? '' : 'distsignature';
+
+ return sprintf <<'MAKE_FRAG', $meta_target, $sign_target;
+create_distdir :
+ $(RM_RF) $(DISTVNAME)
+ $(PERLRUN) "-MExtUtils::Manifest=manicopy,maniread" \
+ -e "manicopy(maniread(),'$(DISTVNAME)', '$(DIST_CP)');"
+
+distdir : create_distdir %s %s
+ $(NOECHO) $(NOOP)
+
+MAKE_FRAG
+
+}
+
+
+=head3 dist_test
+
+Defines a target that produces the distribution in the
+scratch directory, and runs 'perl Makefile.PL; make ;make test' in that
+subdirectory.
+
+=cut
+
+sub dist_test {
+ my($self) = shift;
+
+ my $mpl_args = join " ", map qq["$_"], @ARGV;
+
+ my $test = $self->cd('$(DISTVNAME)',
+ '$(ABSPERLRUN) Makefile.PL '.$mpl_args,
+ '$(MAKE) $(PASTHRU)',
+ '$(MAKE) test $(PASTHRU)'
+ );
+
+ return sprintf <<'MAKE_FRAG', $test;
+disttest : distdir
+ %s
+
+MAKE_FRAG
+
+
+}
+
+
+=head3 xs_dlsyms_arg
+
+Returns command-line arg(s) to linker for file listing dlsyms to export.
+Defaults to returning empty string, can be overridden by e.g. AIX.
+
+=cut
+
+sub xs_dlsyms_arg {
+ return '';
+}
+
+=head3 xs_dlsyms_ext
+
+Returns file-extension for C method's output file,
+including any "." character.
+
+=cut
+
+sub xs_dlsyms_ext {
+ die "Pure virtual method";
+}
+
+=head3 xs_dlsyms_extra
+
+Returns any extra text to be prepended to the C<$extra> argument of
+C.
+
+=cut
+
+sub xs_dlsyms_extra {
+ '';
+}
+
+=head3 xs_dlsyms_iterator
+
+Iterates over necessary shared objects, calling C method
+for each with appropriate arguments.
+
+=cut
+
+sub xs_dlsyms_iterator {
+ my ($self, $attribs) = @_;
+ if ($self->{XSMULTI}) {
+ my @m;
+ for my $ext ($self->_xs_list_basenames) {
+ my @parts = File::Spec->splitdir($ext);
+ shift @parts if $parts[0] eq 'lib';
+ my $name = join '::', @parts;
+ push @m, $self->xs_make_dlsyms(
+ $attribs,
+ $ext . $self->xs_dlsyms_ext,
+ "$ext.xs",
+ $name,
+ $parts[-1],
+ {}, [], {}, [],
+ $self->xs_dlsyms_extra . q!, 'FILE' => ! . neatvalue($ext),
+ );
+ }
+ return join "\n", @m;
+ } else {
+ return $self->xs_make_dlsyms(
+ $attribs,
+ $self->{BASEEXT} . $self->xs_dlsyms_ext,
+ 'Makefile.PL',
+ $self->{NAME},
+ $self->{DLBASE},
+ $attribs->{DL_FUNCS} || $self->{DL_FUNCS} || {},
+ $attribs->{FUNCLIST} || $self->{FUNCLIST} || [],
+ $attribs->{IMPORTS} || $self->{IMPORTS} || {},
+ $attribs->{DL_VARS} || $self->{DL_VARS} || [],
+ $self->xs_dlsyms_extra,
+ );
+ }
+}
+
+=head3 xs_make_dlsyms
+
+ $self->xs_make_dlsyms(
+ \%attribs, # hashref from %attribs in caller
+ "$self->{BASEEXT}.def", # output file for Makefile target
+ 'Makefile.PL', # dependency
+ $self->{NAME}, # shared object's "name"
+ $self->{DLBASE}, # last ::-separated part of name
+ $attribs{DL_FUNCS} || $self->{DL_FUNCS} || {}, # various params
+ $attribs{FUNCLIST} || $self->{FUNCLIST} || [],
+ $attribs{IMPORTS} || $self->{IMPORTS} || {},
+ $attribs{DL_VARS} || $self->{DL_VARS} || [],
+ # optional extra param that will be added as param to Mksymlists
+ );
+
+Utility method that returns Makefile snippet to call C.
+
+=cut
+
+sub xs_make_dlsyms {
+ my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
+ my @m = (
+ "\n$target: $dep\n",
+ q! $(PERLRUN) -MExtUtils::Mksymlists \\
+ -e "Mksymlists('NAME'=>\"!, $name,
+ q!\", 'DLBASE' => '!,$dlbase,
+ # The above two lines quoted differently to work around
+ # a bug in the 4DOS/4NT command line interpreter. The visible
+ # result of the bug was files named q('extension_name',) *with the
+ # single quotes and the comma* in the extension build directories.
+ q!', 'DL_FUNCS' => !,neatvalue($funcs),
+ q!, 'FUNCLIST' => !,neatvalue($funclist),
+ q!, 'IMPORTS' => !,neatvalue($imports),
+ q!, 'DL_VARS' => !, neatvalue($vars)
+ );
+ push @m, $extra if defined $extra;
+ push @m, qq!);"\n!;
+ join '', @m;
+}
+
+=head3 dynamic (o)
+
+Defines the dynamic target.
+
+=cut
+
+sub dynamic {
+# --- Dynamic Loading Sections ---
+
+ my($self) = shift;
+ '
+dynamic :: $(FIRST_MAKEFILE) config $(INST_BOOT) $(INST_DYNAMIC)
+ $(NOECHO) $(NOOP)
+';
+}
+
+
+=head3 makemakerdflt_target
+
+ my $make_frag = $mm->makemakerdflt_target
+
+Returns a make fragment with the makemakerdeflt_target specified.
+This target is the first target in the Makefile, is the default target
+and simply points off to 'all' just in case any make variant gets
+confused or something gets snuck in before the real 'all' target.
+
+=cut
+
+sub makemakerdflt_target {
+ return <<'MAKE_FRAG';
+makemakerdflt : all
+ $(NOECHO) $(NOOP)
+MAKE_FRAG
+
+}
+
+
+=head3 manifypods_target
+
+ my $manifypods_target = $self->manifypods_target;
+
+Generates the manifypods target. This target generates man pages from
+all POD files in MAN1PODS and MAN3PODS.
+
+=cut
+
+sub manifypods_target {
+ my($self) = shift;
+
+ my $man1pods = '';
+ my $man3pods = '';
+ my $dependencies = '';
+
+ # populate manXpods & dependencies:
+ foreach my $name (sort keys %{$self->{MAN1PODS}}, sort keys %{$self->{MAN3PODS}}) {
+ $dependencies .= " \\\n\t$name";
+ }
+
+ my $manify = <{"MAN${num}PODS"};
+ my $p2m = sprintf <<'CMD', "\$(MAN${num}SECTION)", "$]" > 5.008 ? " -u" : "";
+ $(NOECHO) $(POD2MAN) --section=%s --perm_rw=$(PERM_RW)%s
+CMD
+ push @man_cmds, $self->split_command($p2m, map {($_,$pods->{$_})} sort keys %$pods);
+ }
+
+ $manify .= "\t\$(NOECHO) \$(NOOP)\n" unless @man_cmds;
+ $manify .= join '', map { "$_\n" } @man_cmds;
+
+ return $manify;
+}
+
+{
+ my $has_cpan_meta;
+ sub _has_cpan_meta {
+ return $has_cpan_meta if defined $has_cpan_meta;
+ return $has_cpan_meta = !!eval {
+ require CPAN::Meta;
+ CPAN::Meta->VERSION(2.112150);
+ 1;
+ };
+ }
+}
+
+=head3 metafile_target
+
+ my $target = $mm->metafile_target;
+
+Generate the metafile target.
+
+Writes the file META.yml (YAML encoded meta-data) and META.json
+(JSON encoded meta-data) about the module in the distdir.
+The format follows Module::Build's as closely as possible.
+
+=cut
+
+sub metafile_target {
+ my $self = shift;
+ return <<'MAKE_FRAG' if $self->{NO_META} or ! _has_cpan_meta();
+metafile :
+ $(NOECHO) $(NOOP)
+MAKE_FRAG
+
+ my $metadata = $self->metafile_data(
+ $self->{META_ADD} || {},
+ $self->{META_MERGE} || {},
+ );
+
+ my $meta = $self->_fix_metadata_before_conversion( $metadata );
+
+ my @write_metayml = $self->stashmeta(
+ $meta->as_string({version => "1.4"}), 'META_new.yml'
+ );
+ my @write_metajson = $self->stashmeta(
+ $meta->as_string({version => "2.0"}), 'META_new.json'
+ );
+
+ my $metayml = join("\n\t", @write_metayml);
+ my $metajson = join("\n\t", @write_metajson);
+ return sprintf <<'MAKE_FRAG', $metayml, $metajson;
+metafile : create_distdir
+ $(NOECHO) $(ECHO) Generating META.yml
+ %s
+ -$(NOECHO) $(MV) META_new.yml $(DISTVNAME)/META.yml
+ $(NOECHO) $(ECHO) Generating META.json
+ %s
+ -$(NOECHO) $(MV) META_new.json $(DISTVNAME)/META.json
+MAKE_FRAG
+
+}
+
+=begin private
+
+=head3 _fix_metadata_before_conversion
+
+ $mm->_fix_metadata_before_conversion( \%metadata );
+
+Fixes errors in the metadata before it's handed off to L for
+conversion. This hopefully results in something that can be used further
+on, no guarantee is made though.
+
+=end private
+
+=cut
+
+sub _fix_metadata_before_conversion {
+ my ( $self, $metadata ) = @_;
+
+ # we should never be called unless this already passed but
+ # prefer to be defensive in case somebody else calls this
+
+ return unless _has_cpan_meta;
+
+ my $bad_version = $metadata->{version} &&
+ !CPAN::Meta::Validator->new->version( 'version', $metadata->{version} );
+ # just delete all invalid versions
+ if( $bad_version ) {
+ warn "Can't parse version '$metadata->{version}'\n";
+ $metadata->{version} = '';
+ }
+
+ my $validator2 = CPAN::Meta::Validator->new( $metadata );
+ my @errors;
+ push @errors, $validator2->errors if !$validator2->is_valid;
+ my $validator14 = CPAN::Meta::Validator->new(
+ {
+ %$metadata,
+ 'meta-spec' => { version => 1.4 },
+ }
+ );
+ push @errors, $validator14->errors if !$validator14->is_valid;
+ # fix non-camelcase custom resource keys (only other trick we know)
+ for my $error ( @errors ) {
+ my ( $key ) = ( $error =~ /Custom resource '(.*)' must be in CamelCase./ );
+ next if !$key;
+
+ # first try to remove all non-alphabetic chars
+ ( my $new_key = $key ) =~ s/[^_a-zA-Z]//g;
+
+ # if that doesn't work, uppercase first one
+ $new_key = ucfirst $new_key if !$validator14->custom_1( $new_key );
+
+ # copy to new key if that worked
+ $metadata->{resources}{$new_key} = $metadata->{resources}{$key}
+ if $validator14->custom_1( $new_key );
+
+ # and delete old one in any case
+ delete $metadata->{resources}{$key};
+ }
+
+ # paper over validation issues, but still complain, necessary because
+ # there's no guarantee that the above will fix ALL errors
+ my $meta = eval { CPAN::Meta->create( $metadata, { lazy_validation => 1 } ) };
+ warn $@ if $@ and
+ $@ !~ /encountered CODE.*, but JSON can only represent references to arrays or hashes/;
+
+ # use the original metadata straight if the conversion failed
+ # or if it can't be stringified.
+ if( !$meta ||
+ !eval { $meta->as_string( { version => $METASPEC_V } ) } ||
+ !eval { $meta->as_string }
+ ) {
+ $meta = bless $metadata, 'CPAN::Meta';
+ }
+
+ my $now_license = $meta->as_struct({ version => 2 })->{license};
+ if ($self->{LICENSE} and $self->{LICENSE} ne 'unknown' and
+ @{$now_license} == 1 and $now_license->[0] eq 'unknown'
+ ) {
+ warn "Invalid LICENSE value '$self->{LICENSE}' ignored\n";
+ }
+
+ $meta;
+}
+
+
+=begin private
+
+=head3 _sort_pairs
+
+ my @pairs = _sort_pairs($sort_sub, \%hash);
+
+Sorts the pairs of a hash based on keys ordered according
+to C<$sort_sub>.
+
+=end private
+
+=cut
+
+sub _sort_pairs {
+ my $sort = shift;
+ my $pairs = shift;
+ return map { $_ => $pairs->{$_} }
+ sort $sort
+ keys %$pairs;
+}
+
+
+# Taken from Module::Build::Base
+sub _hash_merge {
+ my ($self, $h, $k, $v) = @_;
+ if (ref $h->{$k} eq 'ARRAY') {
+ push @{$h->{$k}}, ref $v ? @$v : $v;
+ } elsif (ref $h->{$k} eq 'HASH') {
+ $self->_hash_merge($h->{$k}, $_, $v->{$_}) foreach keys %$v;
+ } else {
+ $h->{$k} = $v;
+ }
+}
+
+
+=head3 metafile_data
+
+ my $metadata_hashref = $mm->metafile_data(\%meta_add, \%meta_merge);
+
+Returns the data which MakeMaker turns into the META.yml file
+and the META.json file. It is always in version 2.0 of the format.
+
+Values of %meta_add will overwrite any existing metadata in those
+keys. %meta_merge will be merged with them.
+
+=cut
+
+sub metafile_data {
+ my $self = shift;
+ my($meta_add, $meta_merge) = @_;
+
+ $meta_add ||= {};
+ $meta_merge ||= {};
+
+ my $version = _normalize_version($self->{VERSION});
+ my $unstable = $version =~ /_/ || $self->{DISTVNAME} =~ /-TRIAL\d*$/;
+ my $release_status = $unstable ? 'unstable' : 'stable';
+ my %meta = (
+ # required
+ abstract => $self->{ABSTRACT} || 'unknown',
+ author => defined($self->{AUTHOR}) ? $self->{AUTHOR} : ['unknown'],
+ dynamic_config => 1,
+ generated_by => "ExtUtils::MakeMaker version $ExtUtils::MakeMaker::VERSION",
+ license => [ $self->{LICENSE} || 'unknown' ],
+ 'meta-spec' => {
+ url => $METASPEC_URL,
+ version => $METASPEC_V,
+ },
+ name => $self->{DISTNAME},
+ release_status => $release_status,
+ version => $version,
+
+ # optional
+ no_index => { directory => [qw(t inc)] },
+ );
+ $self->_add_requirements_to_meta(\%meta);
+
+ if (!eval { require JSON::PP; require CPAN::Meta::Converter; CPAN::Meta::Converter->VERSION(2.141170) }) {
+ return \%meta;
+ }
+
+ # needs to be based on the original version
+ my $v1_add = _metaspec_version($meta_add) !~ /^2/;
+
+ my ($add_v, $merge_v) = map _metaspec_version($_), $meta_add, $meta_merge;
+ for my $frag ($meta_add, $meta_merge) {
+ my $def_v = $frag == $meta_add ? $merge_v : $add_v;
+ $frag = CPAN::Meta::Converter->new($frag, default_version => $def_v)->upgrade_fragment;
+ }
+
+ # if we upgraded a 1.x _ADD fragment, we gave it a prereqs key that
+ # will override all prereqs, which is more than the user asked for;
+ # instead, we'll go inside the prereqs and override all those
+ while( my($key, $val) = each %$meta_add ) {
+ if ($v1_add and $key eq 'prereqs') {
+ $meta{$key}{$_} = $val->{$_} for keys %$val;
+ } elsif ($key ne 'meta-spec') {
+ $meta{$key} = $val;
+ }
+ }
+
+ while( my($key, $val) = each %$meta_merge ) {
+ next if $key eq 'meta-spec';
+ $self->_hash_merge(\%meta, $key, $val);
+ }
+
+ return \%meta;
+}
+
+
+=begin private
+
+=cut
+
+sub _add_requirements_to_meta {
+ my ( $self, $meta ) = @_;
+ # Check the original args so we can tell between the user setting it
+ # to an empty hash and it just being initialized.
+ $meta->{prereqs}{configure}{requires} = $self->{ARGS}{CONFIGURE_REQUIRES}
+ ? $self->{CONFIGURE_REQUIRES}
+ : { 'ExtUtils::MakeMaker' => 0, };
+ $meta->{prereqs}{build}{requires} = $self->{ARGS}{BUILD_REQUIRES}
+ ? $self->{BUILD_REQUIRES}
+ : { 'ExtUtils::MakeMaker' => 0, };
+ $meta->{prereqs}{test}{requires} = $self->{TEST_REQUIRES}
+ if $self->{ARGS}{TEST_REQUIRES};
+ $meta->{prereqs}{runtime}{requires} = $self->{PREREQ_PM}
+ if $self->{ARGS}{PREREQ_PM};
+ $meta->{prereqs}{runtime}{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
+ if $self->{MIN_PERL_VERSION};
+}
+
+# spec version of given fragment - if not given, assume 1.4
+sub _metaspec_version {
+ my ( $meta ) = @_;
+ return $meta->{'meta-spec'}->{version}
+ if defined $meta->{'meta-spec'}
+ and defined $meta->{'meta-spec'}->{version};
+ return '1.4';
+}
+
+sub _add_requirements_to_meta_v1_4 {
+ my ( $self, $meta ) = @_;
+ # Check the original args so we can tell between the user setting it
+ # to an empty hash and it just being initialized.
+ if( $self->{ARGS}{CONFIGURE_REQUIRES} ) {
+ $meta->{configure_requires} = $self->{CONFIGURE_REQUIRES};
+ } else {
+ $meta->{configure_requires} = {
+ 'ExtUtils::MakeMaker' => 0,
+ };
+ }
+ if( $self->{ARGS}{BUILD_REQUIRES} ) {
+ $meta->{build_requires} = $self->{BUILD_REQUIRES};
+ } else {
+ $meta->{build_requires} = {
+ 'ExtUtils::MakeMaker' => 0,
+ };
+ }
+ if( $self->{ARGS}{TEST_REQUIRES} ) {
+ $meta->{build_requires} = {
+ %{ $meta->{build_requires} },
+ %{ $self->{TEST_REQUIRES} },
+ };
+ }
+ $meta->{requires} = $self->{PREREQ_PM}
+ if defined $self->{PREREQ_PM};
+ $meta->{requires}{perl} = _normalize_version($self->{MIN_PERL_VERSION})
+ if $self->{MIN_PERL_VERSION};
+}
+
+# Adapted from Module::Build::Base
+sub _normalize_version {
+ my ($version) = @_;
+ $version = 0 unless defined $version;
+
+ if ( ref $version eq 'version' ) { # version objects
+ $version = $version->stringify;
+ }
+ elsif ( $version =~ /^[^v][^.]*\.[^.]+\./ ) { # no leading v, multiple dots
+ # normalize string tuples without "v": "1.2.3" -> "v1.2.3"
+ $version = "v$version";
+ }
+ else {
+ # leave alone
+ }
+ return $version;
+}
+
+=head3 _dump_hash
+
+ $yaml = _dump_hash(\%options, %hash);
+
+Implements a fake YAML dumper for a hash given
+as a list of pairs. No quoting/escaping is done. Keys
+are supposed to be strings. Values are undef, strings,
+hash refs or array refs of strings.
+
+Supported options are:
+
+ delta => STR - indentation delta
+ use_header => BOOL - whether to include a YAML header
+ indent => STR - a string of spaces
+ default: ''
+
+ max_key_length => INT - maximum key length used to align
+ keys and values of the same hash
+ default: 20
+ key_sort => CODE - a sort sub
+ It may be undef, which means no sorting by keys
+ default: sub { lc $a cmp lc $b }
+
+ customs => HASH - special options for certain keys
+ (whose values are hashes themselves)
+ may contain: max_key_length, key_sort, customs
+
+=end private
+
+=cut
+
+sub _dump_hash {
+ croak "first argument should be a hash ref" unless ref $_[0] eq 'HASH';
+ my $options = shift;
+ my %hash = @_;
+
+ # Use a list to preserve order.
+ my @pairs;
+
+ my $k_sort
+ = exists $options->{key_sort} ? $options->{key_sort}
+ : sub { lc $a cmp lc $b };
+ if ($k_sort) {
+ croak "'key_sort' should be a coderef" unless ref $k_sort eq 'CODE';
+ @pairs = _sort_pairs($k_sort, \%hash);
+ } else { # list of pairs, no sorting
+ @pairs = @_;
+ }
+
+ my $yaml = $options->{use_header} ? "--- #YAML:1.0\n" : '';
+ my $indent = $options->{indent} || '';
+ my $k_length = min(
+ ($options->{max_key_length} || 20),
+ max(map { length($_) + 1 } grep { !ref $hash{$_} } keys %hash)
+ );
+ my $customs = $options->{customs} || {};
+
+ # printf format for key
+ my $k_format = "%-${k_length}s";
+
+ while( @pairs ) {
+ my($key, $val) = splice @pairs, 0, 2;
+ $val = '~' unless defined $val;
+ if(ref $val eq 'HASH') {
+ if ( keys %$val ) {
+ my %k_options = ( # options for recursive call
+ delta => $options->{delta},
+ use_header => 0,
+ indent => $indent . $options->{delta},
+ );
+ if (exists $customs->{$key}) {
+ my %k_custom = %{$customs->{$key}};
+ foreach my $k (qw(key_sort max_key_length customs)) {
+ $k_options{$k} = $k_custom{$k} if exists $k_custom{$k};
+ }
+ }
+ $yaml .= $indent . "$key:\n"
+ . _dump_hash(\%k_options, %$val);
+ }
+ else {
+ $yaml .= $indent . "$key: {}\n";
+ }
+ }
+ elsif (ref $val eq 'ARRAY') {
+ if( @$val ) {
+ $yaml .= $indent . "$key:\n";
+
+ for (@$val) {
+ croak "only nested arrays of non-refs are supported" if ref $_;
+ $yaml .= $indent . $options->{delta} . "- $_\n";
+ }
+ }
+ else {
+ $yaml .= $indent . "$key: []\n";
+ }
+ }
+ elsif( ref $val and !blessed($val) ) {
+ croak "only nested hashes, arrays and objects are supported";
+ }
+ else { # if it's an object, just stringify it
+ $yaml .= $indent . sprintf "$k_format %s\n", "$key:", $val;
+ }
+ };
+
+ return $yaml;
+
+}
+
+sub blessed {
+ return eval { $_[0]->isa("UNIVERSAL"); };
+}
+
+sub max {
+ return (sort { $b <=> $a } @_)[0];
+}
+
+sub min {
+ return (sort { $a <=> $b } @_)[0];
+}
+
+=head3 metafile_file
+
+ my $meta_yml = $mm->metafile_file(@metadata_pairs);
+
+Turns the @metadata_pairs into YAML.
+
+This method does not implement a complete YAML dumper, being limited
+to dump a hash with values which are strings, undef's or nested hashes
+and arrays of strings. No quoting/escaping is done.
+
+=cut
+
+sub metafile_file {
+ my $self = shift;
+
+ my %dump_options = (
+ use_header => 1,
+ delta => ' ' x 4,
+ key_sort => undef,
+ );
+ return _dump_hash(\%dump_options, @_);
+
+}
+
+
+=head3 distmeta_target
+
+ my $make_frag = $mm->distmeta_target;
+
+Generates the distmeta target to add META.yml and META.json to the MANIFEST
+in the distdir.
+
+=cut
+
+sub distmeta_target {
+ my $self = shift;
+
+ my @add_meta = (
+ $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']),
+exit unless -e q{META.yml};
+eval { maniadd({q{META.yml} => q{Module YAML meta-data (added by MakeMaker)}}) }
+ or die "Could not add META.yml to MANIFEST: ${'@'}"
+CODE
+ $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd'])
+exit unless -f q{META.json};
+eval { maniadd({q{META.json} => q{Module JSON meta-data (added by MakeMaker)}}) }
+ or die "Could not add META.json to MANIFEST: ${'@'}"
+CODE
+ );
+
+ my @add_meta_to_distdir = map { $self->cd('$(DISTVNAME)', $_) } @add_meta;
+
+ return sprintf <<'MAKE', @add_meta_to_distdir;
+distmeta : create_distdir metafile
+ $(NOECHO) %s
+ $(NOECHO) %s
+
+MAKE
+
+}
+
+
+=head3 mymeta
+
+ my $mymeta = $mm->mymeta;
+
+Generate MYMETA information as a hash either from an existing CPAN Meta file
+(META.json or META.yml) or from internal data.
+
+=cut
+
+sub mymeta {
+ my $self = shift;
+ my $file = shift || ''; # for testing
+
+ my $mymeta = $self->_mymeta_from_meta($file);
+ my $v2 = 1;
+
+ unless ( $mymeta ) {
+ $mymeta = $self->metafile_data(
+ $self->{META_ADD} || {},
+ $self->{META_MERGE} || {},
+ );
+ $v2 = 0;
+ }
+
+ # Overwrite the non-configure dependency hashes
+ $self->_add_requirements_to_meta($mymeta);
+
+ $mymeta->{dynamic_config} = 0;
+
+ return $mymeta;
+}
+
+
+sub _mymeta_from_meta {
+ my $self = shift;
+ my $metafile = shift || ''; # for testing
+
+ return unless _has_cpan_meta();
+
+ my $meta;
+ for my $file ( $metafile, "META.json", "META.yml" ) {
+ next unless -e $file;
+ eval {
+ $meta = CPAN::Meta->load_file($file)->as_struct( { version => 2 } );
+ };
+ last if $meta;
+ }
+ return unless $meta;
+
+ # META.yml before 6.25_01 cannot be trusted. META.yml lived in the source directory.
+ # There was a good chance the author accidentally uploaded a stale META.yml if they
+ # rolled their own tarball rather than using "make dist".
+ if ($meta->{generated_by} &&
+ $meta->{generated_by} =~ /ExtUtils::MakeMaker version ([\d\._]+)/) {
+ my $eummv = do { no warnings; $1+0; };
+ if ($eummv < 6.2501) {
+ return;
+ }
+ }
+
+ return $meta;
+}
+
+=head3 write_mymeta
+
+ $self->write_mymeta( $mymeta );
+
+Write MYMETA information to MYMETA.json and MYMETA.yml.
+
+=cut
+
+sub write_mymeta {
+ my $self = shift;
+ my $mymeta = shift;
+
+ return unless _has_cpan_meta();
+
+ my $meta_obj = $self->_fix_metadata_before_conversion( $mymeta );
+
+ $meta_obj->save( 'MYMETA.json', { version => "2.0" } );
+ $meta_obj->save( 'MYMETA.yml', { version => "1.4" } );
+ return 1;
+}
+
+=head3 realclean (o)
+
+Defines the realclean target.
+
+=cut
+
+sub realclean {
+ my($self, %attribs) = @_;
+
+ my @dirs = qw($(DISTVNAME));
+ my @files = qw($(FIRST_MAKEFILE) $(MAKEFILE_OLD));
+
+ # Special exception for the perl core where INST_* is not in blib.
+ # This cleans up the files built from the ext/ directory (all XS).
+ if( $self->{PERL_CORE} ) {
+ push @dirs, qw($(INST_AUTODIR) $(INST_ARCHAUTODIR));
+ push @files, values %{$self->{PM}};
+ }
+
+ if( $self->has_link_code ){
+ push @files, qw($(OBJECT));
+ }
+
+ if( $attribs{FILES} ) {
+ if( ref $attribs{FILES} ) {
+ push @dirs, @{ $attribs{FILES} };
+ }
+ else {
+ push @dirs, split /\s+/, $attribs{FILES};
+ }
+ }
+
+ # Occasionally files are repeated several times from different sources
+ { my(%f) = map { ($_ => 1) } @files; @files = sort keys %f; }
+ { my(%d) = map { ($_ => 1) } @dirs; @dirs = sort keys %d; }
+
+ my $rm_cmd = join "\n\t", map { "$_" }
+ $self->split_command('- $(RM_F)', @files);
+ my $rmf_cmd = join "\n\t", map { "$_" }
+ $self->split_command('- $(RM_RF)', @dirs);
+
+ my $m = sprintf <<'MAKE', $rm_cmd, $rmf_cmd;
+# Delete temporary files (via clean) and also delete dist files
+realclean purge :: realclean_subdirs
+ %s
+ %s
+MAKE
+
+ $m .= "\t$attribs{POSTOP}\n" if $attribs{POSTOP};
+
+ return $m;
+}
+
+
+=head3 realclean_subdirs_target
+
+ my $make_frag = $MM->realclean_subdirs_target;
+
+Returns the realclean_subdirs target. This is used by the realclean
+target to call realclean on any subdirectories which contain Makefiles.
+
+=cut
+
+sub realclean_subdirs_target {
+ my $self = shift;
+ my @m = <<'EOF';
+# so clean is forced to complete before realclean_subdirs runs
+realclean_subdirs : clean
+EOF
+ return join '', @m, "\t\$(NOECHO) \$(NOOP)\n" unless @{$self->{DIR}};
+ foreach my $dir (@{$self->{DIR}}) {
+ foreach my $makefile ('$(MAKEFILE_OLD)', '$(FIRST_MAKEFILE)' ) {
+ my $subrclean .= $self->oneliner(_sprintf562 <<'CODE', $dir, $makefile);
+chdir '%1$s'; system '$(MAKE) $(USEMAKEFILE) %2$s realclean' if -f '%2$s';
+CODE
+ push @m, "\t- $subrclean\n";
+ }
+ }
+ return join '', @m;
+}
+
+
+=head3 signature_target
+
+ my $target = $mm->signature_target;
+
+Generate the signature target.
+
+Writes the file SIGNATURE with "cpansign -s".
+
+=cut
+
+sub signature_target {
+ my $self = shift;
+
+ return <<'MAKE_FRAG';
+signature :
+ cpansign -s
+MAKE_FRAG
+
+}
+
+
+=head3 distsignature_target
+
+ my $make_frag = $mm->distsignature_target;
+
+Generates the distsignature target to add SIGNATURE to the MANIFEST in the
+distdir.
+
+=cut
+
+sub distsignature_target {
+ my $self = shift;
+
+ my $add_sign = $self->oneliner(<<'CODE', ['-MExtUtils::Manifest=maniadd']);
+eval { maniadd({q{SIGNATURE} => q{Public-key signature (added by MakeMaker)}}) }
+ or die "Could not add SIGNATURE to MANIFEST: ${'@'}"
+CODE
+
+ my $sign_dist = $self->cd('$(DISTVNAME)' => 'cpansign -s');
+
+ # cpansign -s complains if SIGNATURE is in the MANIFEST yet does not
+ # exist
+ my $touch_sig = $self->cd('$(DISTVNAME)' => '$(TOUCH) SIGNATURE');
+ my $add_sign_to_dist = $self->cd('$(DISTVNAME)' => $add_sign );
+
+ return sprintf <<'MAKE', $add_sign_to_dist, $touch_sig, $sign_dist
+distsignature : distmeta
+ $(NOECHO) %s
+ $(NOECHO) %s
+ %s
+
+MAKE
+
+}
+
+
+=head3 special_targets
+
+ my $make_frag = $mm->special_targets
+
+Returns a make fragment containing any targets which have special
+meaning to make. For example, .SUFFIXES and .PHONY.
+
+=cut
+
+sub special_targets {
+ my $make_frag = <<'MAKE_FRAG';
+.SUFFIXES : .xs .c .C .cpp .i .s .cxx .cc $(OBJ_EXT)
+
+.PHONY: all config static dynamic test linkext manifest blibdirs clean realclean disttest distdir pure_all subdirs clean_subdirs makemakerdflt manifypods realclean_subdirs subdirs_dynamic subdirs_pure_nolink subdirs_static subdirs-test_dynamic subdirs-test_static test_dynamic test_static
+
+MAKE_FRAG
+
+ $make_frag .= <<'MAKE_FRAG' if $ENV{CLEARCASE_ROOT};
+.NO_CONFIG_REC: Makefile
+
+MAKE_FRAG
+
+ return $make_frag;
+}
+
+
+
+
+=head2 Init methods
+
+Methods which help initialize the MakeMaker object and macros.
+
+
+=head3 init_ABSTRACT
+
+ $mm->init_ABSTRACT
+
+=cut
+
+sub init_ABSTRACT {
+ my $self = shift;
+
+ if( $self->{ABSTRACT_FROM} and $self->{ABSTRACT} ) {
+ warn "Both ABSTRACT_FROM and ABSTRACT are set. ".
+ "Ignoring ABSTRACT_FROM.\n";
+ return;
+ }
+
+ if ($self->{ABSTRACT_FROM}){
+ $self->{ABSTRACT} = $self->parse_abstract($self->{ABSTRACT_FROM}) or
+ carp "WARNING: Setting ABSTRACT via file ".
+ "'$self->{ABSTRACT_FROM}' failed\n";
+ }
+
+ if ($self->{ABSTRACT} && $self->{ABSTRACT} =~ m![[:cntrl:]]+!) {
+ warn "WARNING: ABSTRACT contains control character(s),".
+ " they will be removed\n";
+ $self->{ABSTRACT} =~ s![[:cntrl:]]+!!g;
+ return;
+ }
+}
+
+=head3 init_INST
+
+ $mm->init_INST;
+
+Called by init_main. Sets up all INST_* variables except those related
+to XS code. Those are handled in init_xs.
+
+=cut
+
+sub init_INST {
+ my($self) = shift;
+
+ $self->{INST_ARCHLIB} ||= $self->catdir($Curdir,"blib","arch");
+ $self->{INST_BIN} ||= $self->catdir($Curdir,'blib','bin');
+
+ # INST_LIB typically pre-set if building an extension after
+ # perl has been built and installed. Setting INST_LIB allows
+ # you to build directly into, say $Config{privlibexp}.
+ unless ($self->{INST_LIB}){
+ if ($self->{PERL_CORE}) {
+ $self->{INST_LIB} = $self->{INST_ARCHLIB} = $self->{PERL_LIB};
+ } else {
+ $self->{INST_LIB} = $self->catdir($Curdir,"blib","lib");
+ }
+ }
+
+ my @parentdir = split(/::/, $self->{PARENT_NAME});
+ $self->{INST_LIBDIR} = $self->catdir('$(INST_LIB)', @parentdir);
+ $self->{INST_ARCHLIBDIR} = $self->catdir('$(INST_ARCHLIB)', @parentdir);
+ $self->{INST_AUTODIR} = $self->catdir('$(INST_LIB)', 'auto',
+ '$(FULLEXT)');
+ $self->{INST_ARCHAUTODIR} = $self->catdir('$(INST_ARCHLIB)', 'auto',
+ '$(FULLEXT)');
+
+ $self->{INST_SCRIPT} ||= $self->catdir($Curdir,'blib','script');
+
+ $self->{INST_MAN1DIR} ||= $self->catdir($Curdir,'blib','man1');
+ $self->{INST_MAN3DIR} ||= $self->catdir($Curdir,'blib','man3');
+
+ return 1;
+}
+
+
+=head3 init_INSTALL
+
+ $mm->init_INSTALL;
+
+Called by init_main. Sets up all INSTALL_* variables (except
+INSTALLDIRS) and *PREFIX.
+
+=cut
+
+sub init_INSTALL {
+ my($self) = shift;
+
+ if( $self->{ARGS}{INSTALL_BASE} and $self->{ARGS}{PREFIX} ) {
+ die "Only one of PREFIX or INSTALL_BASE can be given. Not both.\n";
+ }
+
+ if( $self->{ARGS}{INSTALL_BASE} ) {
+ $self->init_INSTALL_from_INSTALL_BASE;
+ }
+ else {
+ $self->init_INSTALL_from_PREFIX;
+ }
+}
+
+
+=head3 init_INSTALL_from_PREFIX
+
+ $mm->init_INSTALL_from_PREFIX;
+
+=cut
+
+sub init_INSTALL_from_PREFIX {
+ my $self = shift;
+
+ $self->init_lib2arch;
+
+ # There are often no Config.pm defaults for these new man variables so
+ # we fall back to the old behavior which is to use installman*dir
+ foreach my $num (1, 3) {
+ my $k = 'installsiteman'.$num.'dir';
+
+ $self->{uc $k} ||= uc "\$(installman${num}dir)"
+ unless $Config{$k};
+ }
+
+ foreach my $num (1, 3) {
+ my $k = 'installvendorman'.$num.'dir';
+
+ unless( $Config{$k} ) {
+ $self->{uc $k} ||= $Config{usevendorprefix}
+ ? uc "\$(installman${num}dir)"
+ : '';
+ }
+ }
+
+ $self->{INSTALLSITEBIN} ||= '$(INSTALLBIN)'
+ unless $Config{installsitebin};
+ $self->{INSTALLSITESCRIPT} ||= '$(INSTALLSCRIPT)'
+ unless $Config{installsitescript};
+
+ unless( $Config{installvendorbin} ) {
+ $self->{INSTALLVENDORBIN} ||= $Config{usevendorprefix}
+ ? $Config{installbin}
+ : '';
+ }
+ unless( $Config{installvendorscript} ) {
+ $self->{INSTALLVENDORSCRIPT} ||= $Config{usevendorprefix}
+ ? $Config{installscript}
+ : '';
+ }
+
+
+ my $iprefix = $Config{installprefixexp} || $Config{installprefix} ||
+ $Config{prefixexp} || $Config{prefix} || '';
+ my $vprefix = $Config{usevendorprefix} ? $Config{vendorprefixexp} : '';
+ my $sprefix = $Config{siteprefixexp} || '';
+
+ # 5.005_03 doesn't have a siteprefix.
+ $sprefix = $iprefix unless $sprefix;
+
+
+ $self->{PREFIX} ||= '';
+
+ if( $self->{PREFIX} ) {
+ @{$self}{qw(PERLPREFIX SITEPREFIX VENDORPREFIX)} =
+ ('$(PREFIX)') x 3;
+ }
+ else {
+ $self->{PERLPREFIX} ||= $iprefix;
+ $self->{SITEPREFIX} ||= $sprefix;
+ $self->{VENDORPREFIX} ||= $vprefix;
+
+ # Lots of MM extension authors like to use $(PREFIX) so we
+ # put something sensible in there no matter what.
+ $self->{PREFIX} = '$('.uc $self->{INSTALLDIRS}.'PREFIX)';
+ }
+
+ my $arch = $Config{archname};
+ my $version = $Config{version};
+
+ # default style
+ my $libstyle = $Config{installstyle} || 'lib/perl5';
+ my $manstyle = '';
+
+ if( $self->{LIBSTYLE} ) {
+ $libstyle = $self->{LIBSTYLE};
+ $manstyle = $self->{LIBSTYLE} eq 'lib/perl5' ? 'lib/perl5' : '';
+ }
+
+ # Some systems, like VOS, set installman*dir to '' if they can't
+ # read man pages.
+ for my $num (1, 3) {
+ $self->{'INSTALLMAN'.$num.'DIR'} ||= 'none'
+ unless $Config{'installman'.$num.'dir'};
+ }
+
+ my %bin_layouts =
+ (
+ bin => { s => $iprefix,
+ t => 'perl',
+ d => 'bin' },
+ vendorbin => { s => $vprefix,
+ t => 'vendor',
+ d => 'bin' },
+ sitebin => { s => $sprefix,
+ t => 'site',
+ d => 'bin' },
+ script => { s => $iprefix,
+ t => 'perl',
+ d => 'bin' },
+ vendorscript=> { s => $vprefix,
+ t => 'vendor',
+ d => 'bin' },
+ sitescript => { s => $sprefix,
+ t => 'site',
+ d => 'bin' },
+ );
+
+ my %man_layouts =
+ (
+ man1dir => { s => $iprefix,
+ t => 'perl',
+ d => 'man/man1',
+ style => $manstyle, },
+ siteman1dir => { s => $sprefix,
+ t => 'site',
+ d => 'man/man1',
+ style => $manstyle, },
+ vendorman1dir => { s => $vprefix,
+ t => 'vendor',
+ d => 'man/man1',
+ style => $manstyle, },
+
+ man3dir => { s => $iprefix,
+ t => 'perl',
+ d => 'man/man3',
+ style => $manstyle, },
+ siteman3dir => { s => $sprefix,
+ t => 'site',
+ d => 'man/man3',
+ style => $manstyle, },
+ vendorman3dir => { s => $vprefix,
+ t => 'vendor',
+ d => 'man/man3',
+ style => $manstyle, },
+ );
+
+ my %lib_layouts =
+ (
+ privlib => { s => $iprefix,
+ t => 'perl',
+ d => '',
+ style => $libstyle, },
+ vendorlib => { s => $vprefix,
+ t => 'vendor',
+ d => '',
+ style => $libstyle, },
+ sitelib => { s => $sprefix,
+ t => 'site',
+ d => 'site_perl',
+ style => $libstyle, },
+
+ archlib => { s => $iprefix,
+ t => 'perl',
+ d => "$version/$arch",
+ style => $libstyle },
+ vendorarch => { s => $vprefix,
+ t => 'vendor',
+ d => "$version/$arch",
+ style => $libstyle },
+ sitearch => { s => $sprefix,
+ t => 'site',
+ d => "site_perl/$version/$arch",
+ style => $libstyle },
+ );
+
+
+ # Special case for LIB.
+ if( $self->{LIB} ) {
+ foreach my $var (keys %lib_layouts) {
+ my $Installvar = uc "install$var";
+
+ if( $var =~ /arch/ ) {
+ $self->{$Installvar} ||=
+ $self->catdir($self->{LIB}, $Config{archname});
+ }
+ else {
+ $self->{$Installvar} ||= $self->{LIB};
+ }
+ }
+ }
+
+ my %type2prefix = ( perl => 'PERLPREFIX',
+ site => 'SITEPREFIX',
+ vendor => 'VENDORPREFIX'
+ );
+
+ my %layouts = (%bin_layouts, %man_layouts, %lib_layouts);
+ while( my($var, $layout) = each(%layouts) ) {
+ my($s, $t, $d, $style) = @{$layout}{qw(s t d style)};
+ my $r = '$('.$type2prefix{$t}.')';
+
+ warn "Prefixing $var\n" if $Verbose >= 2;
+
+ my $installvar = "install$var";
+ my $Installvar = uc $installvar;
+ next if $self->{$Installvar};
+
+ $d = "$style/$d" if $style;
+ $self->prefixify($installvar, $s, $r, $d);
+
+ warn " $Installvar == $self->{$Installvar}\n"
+ if $Verbose >= 2;
+ }
+
+ # Generate these if they weren't figured out.
+ $self->{VENDORARCHEXP} ||= $self->{INSTALLVENDORARCH};
+ $self->{VENDORLIBEXP} ||= $self->{INSTALLVENDORLIB};
+
+ return 1;
+}
+
+
+=head3 init_from_INSTALL_BASE
+
+ $mm->init_from_INSTALL_BASE
+
+=cut
+
+my %map = (
+ lib => [qw(lib perl5)],
+ arch => [('lib', 'perl5', $Config{archname})],
+ bin => [qw(bin)],
+ man1dir => [qw(man man1)],
+ man3dir => [qw(man man3)]
+ );
+$map{script} = $map{bin};
+
+sub init_INSTALL_from_INSTALL_BASE {
+ my $self = shift;
+
+ @{$self}{qw(PREFIX VENDORPREFIX SITEPREFIX PERLPREFIX)} =
+ '$(INSTALL_BASE)';
+
+ my %install;
+ foreach my $thing (keys %map) {
+ foreach my $dir (('', 'SITE', 'VENDOR')) {
+ my $uc_thing = uc $thing;
+ my $key = "INSTALL".$dir.$uc_thing;
+
+ $install{$key} ||=
+ ($thing =~ /^man.dir$/ and not $Config{lc $key})
+ ? 'none'
+ : $self->catdir('$(INSTALL_BASE)', @{$map{$thing}});
+ }
+ }
+
+ # Adjust for variable quirks.
+ $install{INSTALLARCHLIB} ||= delete $install{INSTALLARCH};
+ $install{INSTALLPRIVLIB} ||= delete $install{INSTALLLIB};
+
+ foreach my $key (keys %install) {
+ $self->{$key} ||= $install{$key};
+ }
+
+ return 1;
+}
+
+
+=head3 init_VERSION I
+
+ $mm->init_VERSION
+
+Initialize macros representing versions of MakeMaker and other tools
+
+MAKEMAKER: path to the MakeMaker module.
+
+MM_VERSION: ExtUtils::MakeMaker Version
+
+MM_REVISION: ExtUtils::MakeMaker version control revision (for backwards
+ compat)
+
+VERSION: version of your module
+
+VERSION_MACRO: which macro represents the version (usually 'VERSION')
+
+VERSION_SYM: like version but safe for use as an RCS revision number
+
+DEFINE_VERSION: -D line to set the module version when compiling
+
+XS_VERSION: version in your .xs file. Defaults to $(VERSION)
+
+XS_VERSION_MACRO: which macro represents the XS version.
+
+XS_DEFINE_VERSION: -D line to set the xs version when compiling.
+
+Called by init_main.
+
+=cut
+
+sub init_VERSION {
+ my($self) = shift;
+
+ $self->{MAKEMAKER} = $ExtUtils::MakeMaker::Filename;
+ $self->{MM_VERSION} = $ExtUtils::MakeMaker::VERSION;
+ $self->{MM_REVISION}= $ExtUtils::MakeMaker::Revision;
+ $self->{VERSION_FROM} ||= '';
+
+ if ($self->{VERSION_FROM}){
+ $self->{VERSION} = $self->parse_version($self->{VERSION_FROM});
+ if( $self->{VERSION} eq 'undef' ) {
+ carp("WARNING: Setting VERSION via file ".
+ "'$self->{VERSION_FROM}' failed\n");
+ }
+ }
+
+ if (defined $self->{VERSION}) {
+ if ( $self->{VERSION} !~ /^\s*v?[\d_\.]+\s*$/ ) {
+ require version;
+ my $normal = eval { version->new( $self->{VERSION} ) };
+ $self->{VERSION} = $normal if defined $normal;
+ }
+ $self->{VERSION} =~ s/^\s+//;
+ $self->{VERSION} =~ s/\s+$//;
+ }
+ else {
+ $self->{VERSION} = '';
+ }
+
+
+ $self->{VERSION_MACRO} = 'VERSION';
+ ($self->{VERSION_SYM} = $self->{VERSION}) =~ s/\W/_/g;
+ $self->{DEFINE_VERSION} = '-D$(VERSION_MACRO)=\"$(VERSION)\"';
+
+
+ # Graham Barr and Paul Marquess had some ideas how to ensure
+ # version compatibility between the *.pm file and the
+ # corresponding *.xs file. The bottom line was, that we need an
+ # XS_VERSION macro that defaults to VERSION:
+ $self->{XS_VERSION} ||= $self->{VERSION};
+
+ $self->{XS_VERSION_MACRO} = 'XS_VERSION';
+ $self->{XS_DEFINE_VERSION} = '-D$(XS_VERSION_MACRO)=\"$(XS_VERSION)\"';
+
+}
+
+
+=head3 init_tools
+
+ $MM->init_tools();
+
+Initializes the simple macro definitions used by tools_other() and
+places them in the $MM object. These use conservative cross platform
+versions and should be overridden with platform specific versions for
+performance.
+
+Defines at least these macros.
+
+ Macro Description
+
+ NOOP Do nothing
+ NOECHO Tell make not to display the command itself
+
+ SHELL Program used to run shell commands
+
+ ECHO Print text adding a newline on the end
+ RM_F Remove a file
+ RM_RF Remove a directory
+ TOUCH Update a file's timestamp
+ TEST_F Test for a file's existence
+ TEST_S Test the size of a file
+ CP Copy a file
+ CP_NONEMPTY Copy a file if it is not empty
+ MV Move a file
+ CHMOD Change permissions on a file
+ FALSE Exit with non-zero
+ TRUE Exit with zero
+
+ UMASK_NULL Nullify umask
+ DEV_NULL Suppress all command output
+
+=cut
+
+sub init_tools {
+ my $self = shift;
+
+ $self->{ECHO} ||= $self->oneliner('binmode STDOUT, qq{:raw}; print qq{@ARGV}', ['-l']);
+ $self->{ECHO_N} ||= $self->oneliner('print qq{@ARGV}');
+
+ $self->{TOUCH} ||= $self->oneliner('touch', ["-MExtUtils::Command"]);
+ $self->{CHMOD} ||= $self->oneliner('chmod', ["-MExtUtils::Command"]);
+ $self->{RM_F} ||= $self->oneliner('rm_f', ["-MExtUtils::Command"]);
+ $self->{RM_RF} ||= $self->oneliner('rm_rf', ["-MExtUtils::Command"]);
+ $self->{TEST_F} ||= $self->oneliner('test_f', ["-MExtUtils::Command"]);
+ $self->{TEST_S} ||= $self->oneliner('test_s', ["-MExtUtils::Command::MM"]);
+ $self->{CP_NONEMPTY} ||= $self->oneliner('cp_nonempty', ["-MExtUtils::Command::MM"]);
+ $self->{FALSE} ||= $self->oneliner('exit 1');
+ $self->{TRUE} ||= $self->oneliner('exit 0');
+
+ $self->{MKPATH} ||= $self->oneliner('mkpath', ["-MExtUtils::Command"]);
+
+ $self->{CP} ||= $self->oneliner('cp', ["-MExtUtils::Command"]);
+ $self->{MV} ||= $self->oneliner('mv', ["-MExtUtils::Command"]);
+
+ $self->{MOD_INSTALL} ||=
+ $self->oneliner(<<'CODE', ['-MExtUtils::Install']);
+install([ from_to => {@ARGV}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]);
+CODE
+ $self->{DOC_INSTALL} ||= $self->oneliner('perllocal_install', ["-MExtUtils::Command::MM"]);
+ $self->{UNINSTALL} ||= $self->oneliner('uninstall', ["-MExtUtils::Command::MM"]);
+ $self->{WARN_IF_OLD_PACKLIST} ||=
+ $self->oneliner('warn_if_old_packlist', ["-MExtUtils::Command::MM"]);
+ $self->{FIXIN} ||= $self->oneliner('MY->fixin(shift)', ["-MExtUtils::MY"]);
+ $self->{EQUALIZE_TIMESTAMP} ||= $self->oneliner('eqtime', ["-MExtUtils::Command"]);
+
+ $self->{UNINST} ||= 0;
+ $self->{VERBINST} ||= 0;
+
+ $self->{SHELL} ||= $Config{sh};
+
+ # UMASK_NULL is not used by MakeMaker but some CPAN modules
+ # make use of it.
+ $self->{UMASK_NULL} ||= "umask 0";
+
+ # Not the greatest default, but its something.
+ $self->{DEV_NULL} ||= "> /dev/null 2>&1";
+
+ $self->{NOOP} ||= '$(TRUE)';
+ $self->{NOECHO} = '@' unless defined $self->{NOECHO};
+
+ $self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE} || 'Makefile';
+ $self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE};
+ $self->{MAKEFILE_OLD} ||= $self->{MAKEFILE}.'.old';
+ $self->{MAKE_APERL_FILE} ||= $self->{MAKEFILE}.'.aperl';
+
+ # Not everybody uses -f to indicate "use this Makefile instead"
+ $self->{USEMAKEFILE} ||= '-f';
+
+ # Some makes require a wrapper around macros passed in on the command
+ # line.
+ $self->{MACROSTART} ||= '';
+ $self->{MACROEND} ||= '';
+
+ return;
+}
+
+
+=head3 init_others
+
+ $MM->init_others();
+
+Initializes the macro definitions having to do with compiling and
+linking used by tools_other() and places them in the $MM object.
+
+If there is no description, its the same as the parameter to
+WriteMakefile() documented in L.
+
+=cut
+
+sub init_others {
+ my $self = shift;
+
+ $self->{LD_RUN_PATH} = "";
+
+ $self->{LIBS} = $self->_fix_libs($self->{LIBS});
+
+ # Compute EXTRALIBS, BSLOADLIBS and LDLOADLIBS from $self->{LIBS}
+ foreach my $libs ( @{$self->{LIBS}} ) {
+ $libs =~ s/^\s*(.*\S)\s*$/$1/; # remove leading and trailing whitespace
+ my @libs = $self->extliblist($libs);
+ if (grep $_, @libs[0..2]) {
+ # LD_RUN_PATH now computed by ExtUtils::Liblist
+ @$self{qw(EXTRALIBS BSLOADLIBS LDLOADLIBS LD_RUN_PATH)} = @libs;
+ last;
+ }
+ }
+
+ if ( $self->{OBJECT} ) {
+ $self->{OBJECT} = join(" ", @{$self->{OBJECT}}) if ref $self->{OBJECT};
+ $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
+ } elsif ( ($self->{MAGICXS} || $self->{XSMULTI}) && @{$self->{O_FILES}||[]} ) {
+ $self->{OBJECT} = join(" ", @{$self->{O_FILES}});
+ $self->{OBJECT} =~ s!\.o(bj)?\b!\$(OBJ_EXT)!g;
+ } else {
+ # init_dirscan should have found out, if we have C files
+ $self->{OBJECT} = "";
+ $self->{OBJECT} = '$(BASEEXT)$(OBJ_EXT)' if @{$self->{C}||[]};
+ }
+ $self->{OBJECT} =~ s/\n+/ \\\n\t/g;
+
+ $self->{BOOTDEP} = (-f "$self->{BASEEXT}_BS") ? "$self->{BASEEXT}_BS" : "";
+ $self->{PERLMAINCC} ||= '$(CC)';
+ $self->{LDFROM} = '$(OBJECT)' unless $self->{LDFROM};
+
+ # Sanity check: don't define LINKTYPE = dynamic if we're skipping
+ # the 'dynamic' section of MM. We don't have this problem with
+ # 'static', since we either must use it (%Config says we can't
+ # use dynamic loading) or the caller asked for it explicitly.
+ if (!$self->{LINKTYPE}) {
+ $self->{LINKTYPE} = $self->{SKIPHASH}{'dynamic'}
+ ? 'static'
+ : ($Config{usedl} ? 'dynamic' : 'static');
+ }
+
+ return;
+}
+
+
+# Lets look at $self->{LIBS} carefully: It may be an anon array, a string or
+# undefined. In any case we turn it into an anon array
+sub _fix_libs {
+ my($self, $libs) = @_;
+
+ return !defined $libs ? [''] :
+ !ref $libs ? [$libs] :
+ !defined $libs->[0] ? [''] :
+ $libs ;
+}
+
+
+=head3 tools_other
+
+ my $make_frag = $MM->tools_other;
+
+Returns a make fragment containing definitions for the macros init_others()
+initializes.
+
+=cut
+
+sub tools_other {
+ my($self) = shift;
+ my @m;
+
+ my $is_nmake = $self->is_make_type('nmake');
+ push @m, <<'EOF' if $is_nmake;
+EUMM_NMAKE_HASH = ^# # to get hash character into strings - yes, horrible
+EOF
+ # We set PM_FILTER as late as possible so it can see all the earlier
+ # on macro-order sensitive makes such as nmake.
+ for my $tool (qw{ SHELL CHMOD CP MV NOOP NOECHO RM_F RM_RF TEST_F TOUCH
+ UMASK_NULL DEV_NULL MKPATH EQUALIZE_TIMESTAMP
+ FALSE TRUE
+ ECHO ECHO_N
+ UNINST VERBINST
+ MOD_INSTALL DOC_INSTALL UNINSTALL
+ WARN_IF_OLD_PACKLIST
+ MACROSTART MACROEND
+ USEMAKEFILE
+ PM_FILTER
+ FIXIN
+ CP_NONEMPTY
+ } )
+ {
+ next unless defined(my $value = $self->{$tool});
+ # https://learn.microsoft.com/en-us/cpp/build/reference/contents-of-a-makefile?view=msvc-170#special-characters-in-a-makefile
+ if ($is_nmake) {
+ $value =~ s/#/\$(EUMM_NMAKE_HASH)/g
+ } else {
+ $value =~ s/#/\\#/g
+ }
+ push @m, "$tool = $value\n";
+ }
+
+ return join "", @m;
+}
+
+
+=head3 init_DIRFILESEP I
+
+ $MM->init_DIRFILESEP;
+ my $dirfilesep = $MM->{DIRFILESEP};
+
+Initializes the DIRFILESEP macro which is the separator between the
+directory and filename in a filepath. ie. / on Unix, \ on Win32 and
+nothing on VMS.
+
+For example:
+
+ # instead of $(INST_ARCHAUTODIR)/extralibs.ld
+ $(INST_ARCHAUTODIR)$(DIRFILESEP)extralibs.ld
+
+Something of a hack but it prevents a lot of code duplication between
+MM_* variants.
+
+Do not use this as a separator between directories. Some operating
+systems use different separators between subdirectories as between
+directories and filenames (for example: VOLUME:[dir1.dir2]file on VMS).
+
+=head3 init_linker I
+
+ $mm->init_linker;
+
+Initialize macros which have to do with linking.
+
+PERL_ARCHIVE: path to libperl.a equivalent to be linked to dynamic
+extensions.
+
+PERL_ARCHIVE_AFTER: path to a library which should be put on the
+linker command line I the external libraries to be linked to
+dynamic extensions. This may be needed if the linker is one-pass, and
+Perl includes some overrides for C RTL functions, such as malloc().
+
+EXPORT_LIST: name of a file that is passed to linker to define symbols
+to be exported.
+
+Some OSes do not need these in which case leave it blank.
+
+
+=head3 init_platform
+
+ $mm->init_platform
+
+Initialize any macros which are for platform specific use only.
+
+A typical one is the version number of your OS specific module.
+(ie. MM_Unix_VERSION or MM_VMS_VERSION).
+
+=cut
+
+sub init_platform {
+ return '';
+}
+
+
+=head3 init_MAKE
+
+ $mm->init_MAKE
+
+Initialize MAKE from either a MAKE environment variable or $Config{make}.
+
+=cut
+
+sub init_MAKE {
+ my $self = shift;
+
+ $self->{MAKE} ||= $ENV{MAKE} || $Config{make};
+}
+
+
+=head2 Tools
+
+A grab bag of methods to generate specific macros and commands.
+
+
+
+=head3 manifypods
+
+Defines targets and routines to translate the pods into manpages and
+put them into the INST_* directories.
+
+=cut
+
+sub manifypods {
+ my $self = shift;
+
+ my $POD2MAN_macro = $self->POD2MAN_macro();
+ my $manifypods_target = $self->manifypods_target();
+
+ return <POD2MAN_macro
+
+Returns a definition for the POD2MAN macro. This is a program
+which emulates the pod2man utility. You can add more switches to the
+command by simply appending them on the macro.
+
+Typical usage:
+
+ $(POD2MAN) --section=3 --perm_rw=$(PERM_RW) podfile1 man_page1 ...
+
+=cut
+
+sub POD2MAN_macro {
+ my $self = shift;
+
+# Need the trailing '--' so perl stops gobbling arguments and - happens
+# to be an alternative end of line separator on VMS so we quote it
+ return <<'END_OF_DEF';
+POD2MAN_EXE = $(PERLRUN) "-MExtUtils::Command::MM" -e pod2man "--"
+POD2MAN = $(POD2MAN_EXE)
+END_OF_DEF
+}
+
+
+=head3 test_via_harness
+
+ my $command = $mm->test_via_harness($perl, $tests);
+
+Returns a $command line which runs the given set of $tests with
+Test::Harness and the given $perl.
+
+Used on the t/*.t files.
+
+=cut
+
+sub test_via_harness {
+ my($self, $perl, $tests) = @_;
+
+ return qq{\t$perl "-MExtUtils::Command::MM" "-MTest::Harness" }.
+ qq{"-e" "undef *Test::Harness::Switches; test_harness(\$(TEST_VERBOSE), '\$(INST_LIB)', '\$(INST_ARCHLIB)')" $tests\n};
+}
+
+=head3 test_via_script
+
+ my $command = $mm->test_via_script($perl, $script);
+
+Returns a $command line which just runs a single test without
+Test::Harness. No checks are done on the results, they're just
+printed.
+
+Used for test.pl, since they don't always follow Test::Harness
+formatting.
+
+=cut
+
+sub test_via_script {
+ my($self, $perl, $script) = @_;
+ return qq{\t$perl "-I\$(INST_LIB)" "-I\$(INST_ARCHLIB)" $script\n};
+}
+
+
+=head3 tool_autosplit
+
+Defines a simple perl call that runs autosplit. May be deprecated by
+pm_to_blib soon.
+
+=cut
+
+sub tool_autosplit {
+ my($self, %attribs) = @_;
+
+ my $maxlen = $attribs{MAXLEN} ? '$$AutoSplit::Maxlen=$attribs{MAXLEN};'
+ : '';
+
+ my $asplit = $self->oneliner(sprintf <<'PERL_CODE', $maxlen);
+use AutoSplit; %s autosplit($$ARGV[0], $$ARGV[1], 0, 1, 1)
+PERL_CODE
+
+ return sprintf <<'MAKE_FRAG', $asplit;
+# Usage: $(AUTOSPLITFILE) FileToSplit AutoDirToSplitInto
+AUTOSPLITFILE = %s
+
+MAKE_FRAG
+
+}
+
+
+=head3 arch_check
+
+ my $arch_ok = $mm->arch_check(
+ $INC{"Config.pm"},
+ File::Spec->catfile($Config{archlibexp}, "Config.pm")
+ );
+
+A sanity check that what Perl thinks the architecture is and what
+Config thinks the architecture is are the same. If they're not it
+will return false and show a diagnostic message.
+
+When building Perl it will always return true, as nothing is installed
+yet.
+
+The interface is a bit odd because this is the result of a
+quick refactoring. Don't rely on it.
+
+=cut
+
+sub arch_check {
+ my $self = shift;
+ my($pconfig, $cconfig) = @_;
+
+ return 1 if $self->{PERL_SRC};
+
+ my($pvol, $pthinks) = $self->splitpath($pconfig);
+ my($cvol, $cthinks) = $self->splitpath($cconfig);
+
+ $pthinks = $self->canonpath($pthinks);
+ $cthinks = $self->canonpath($cthinks);
+
+ my $ret = 1;
+ if ($pthinks ne $cthinks) {
+ print "Have $pthinks\n";
+ print "Want $cthinks\n";
+
+ $ret = 0;
+
+ my $arch = (grep length, $self->splitdir($pthinks))[-1];
+
+ print <{UNINSTALLED_PERL};
+Your perl and your Config.pm seem to have different ideas about the
+architecture they are running on.
+Perl thinks: [$arch]
+Config says: [$Config{archname}]
+This may or may not cause problems. Please check your installation of perl
+if you have problems building this extension.
+END
+ }
+
+ return $ret;
+}
+
+
+
+=head2 File::Spec wrappers
+
+ExtUtils::MM_Any is a subclass of L. The methods noted here
+override File::Spec.
+
+
+
+=head3 catfile
+
+File::Spec <= 0.83 has a bug where the file part of catfile is not
+canonicalized. This override fixes that bug.
+
+=cut
+
+sub catfile {
+ my $self = shift;
+ return $self->canonpath($self->SUPER::catfile(@_));
+}
+
+
+
+=head2 Misc
+
+Methods I can't really figure out where they should go yet.
+
+
+=head3 find_tests
+
+ my $test = $mm->find_tests;
+
+Returns a string suitable for feeding to the shell to return all
+tests in t/*.t.
+
+=cut
+
+sub find_tests {
+ my($self) = shift;
+ return -d 't' ? 't/*.t' : '';
+}
+
+=head3 find_tests_recursive
+
+ my $tests = $mm->find_tests_recursive;
+
+Returns a string suitable for feeding to the shell to return all
+tests in t/ but recursively. Equivalent to
+
+ my $tests = $mm->find_tests_recursive_in('t');
+
+=cut
+
+sub find_tests_recursive {
+ my $self = shift;
+ return $self->find_tests_recursive_in('t');
+}
+
+=head3 find_tests_recursive_in
+
+ my $tests = $mm->find_tests_recursive_in($dir);
+
+Returns a string suitable for feeding to the shell to return all
+tests in $dir recursively.
+
+=cut
+
+sub find_tests_recursive_in {
+ my($self, $dir) = @_;
+ return '' unless -d $dir;
+
+ require File::Find;
+
+ my $base_depth = grep { $_ ne '' } File::Spec->splitdir( (File::Spec->splitpath($dir))[1] );
+ my %depths;
+
+ my $wanted = sub {
+ return unless m!\.t$!;
+ my ($volume,$directories,$file) =
+ File::Spec->splitpath( $File::Find::name );
+ my $depth = grep { $_ ne '' } File::Spec->splitdir( $directories );
+ $depth -= $base_depth;
+ $depths{ $depth } = 1;
+ };
+
+ File::Find::find( $wanted, $dir );
+
+ return join ' ',
+ map { $dir . '/*' x $_ . '.t' }
+ sort { $a <=> $b }
+ keys %depths;
+}
+
+=head3 extra_clean_files
+
+ my @files_to_clean = $MM->extra_clean_files;
+
+Returns a list of OS specific files to be removed in the clean target in
+addition to the usual set.
+
+=cut
+
+# An empty method here tickled a perl 5.8.1 bug and would return its object.
+sub extra_clean_files {
+ return;
+}
+
+
+=head3 installvars
+
+ my @installvars = $mm->installvars;
+
+A list of all the INSTALL* variables without the INSTALL prefix. Useful
+for iteration or building related variable sets.
+
+=cut
+
+sub installvars {
+ return qw(PRIVLIB SITELIB VENDORLIB
+ ARCHLIB SITEARCH VENDORARCH
+ BIN SITEBIN VENDORBIN
+ SCRIPT SITESCRIPT VENDORSCRIPT
+ MAN1DIR SITEMAN1DIR VENDORMAN1DIR
+ MAN3DIR SITEMAN3DIR VENDORMAN3DIR
+ );
+}
+
+
+=head3 libscan
+
+ my $wanted = $self->libscan($path);
+
+Takes a path to a file or dir and returns an empty string if we don't
+want to include this file in the library. Otherwise it returns the
+the $path unchanged.
+
+Mainly used to exclude version control administrative directories
+and base-level F from installation.
+
+=cut
+
+sub libscan {
+ my($self,$path) = @_;
+
+ if ($path =~ m<^README\.pod$>i) {
+ warn "WARNING: Older versions of ExtUtils::MakeMaker may errantly install $path as part of this distribution. It is recommended to avoid using this path in CPAN modules.\n";
+ return '';
+ }
+
+ my($dirs,$file) = ($self->splitpath($path))[1,2];
+ return '' if grep /^(?:RCS|CVS|SCCS|\.svn|_darcs)$/,
+ $self->splitdir($dirs), $file;
+
+ return $path;
+}
+
+
+=head3 platform_constants
+
+ my $make_frag = $mm->platform_constants
+
+Returns a make fragment defining all the macros initialized in
+init_platform() rather than put them in constants().
+
+=cut
+
+sub platform_constants {
+ return '';
+}
+
+=head3 post_constants (o)
+
+Returns an empty string per default. Dedicated to overrides from
+within Makefile.PL after all constants have been defined.
+
+=cut
+
+sub post_constants {
+ "";
+}
+
+=head3 post_initialize (o)
+
+Returns an empty string per default. Used in Makefile.PLs to add some
+chunk of text to the Makefile after the object is initialized.
+
+=cut
+
+sub post_initialize {
+ "";
+}
+
+=head3 postamble (o)
+
+Returns an empty string. Can be used in Makefile.PLs to write some
+text to the Makefile at the end.
+
+=cut
+
+sub postamble {
+ "";
+}
+
+=begin private
+
+=head3 _PREREQ_PRINT
+
+ $self->_PREREQ_PRINT;
+
+Implements PREREQ_PRINT.
+
+Refactored out of MakeMaker->new().
+
+=end private
+
+=cut
+
+sub _PREREQ_PRINT {
+ my $self = shift;
+
+ require Data::Dumper;
+ my @what = ('PREREQ_PM');
+ push @what, 'MIN_PERL_VERSION' if $self->{MIN_PERL_VERSION};
+ push @what, 'BUILD_REQUIRES' if $self->{BUILD_REQUIRES};
+ print Data::Dumper->Dump([@{$self}{@what}], \@what);
+ exit 0;
+}
+
+
+=begin private
+
+=head3 _PRINT_PREREQ
+
+ $mm->_PRINT_PREREQ;
+
+Implements PRINT_PREREQ, a slightly different version of PREREQ_PRINT
+added by Redhat to, I think, support generating RPMs from Perl modules.
+
+Should not include BUILD_REQUIRES as RPMs do not include them.
+
+Refactored out of MakeMaker->new().
+
+=end private
+
+=cut
+
+sub _PRINT_PREREQ {
+ my $self = shift;
+
+ my $prereqs= $self->{PREREQ_PM};
+ my @prereq = map { [$_, $prereqs->{$_}] } keys %$prereqs;
+
+ if ( $self->{MIN_PERL_VERSION} ) {
+ push @prereq, ['perl' => $self->{MIN_PERL_VERSION}];
+ }
+
+ print join(" ", map { "perl($_->[0])>=$_->[1] " }
+ sort { $a->[0] cmp $b->[0] } @prereq), "\n";
+ exit 0;
+}
+
+
+=begin private
+
+=head3 _perl_header_files
+
+ my $perl_header_files= $self->_perl_header_files;
+
+returns a sorted list of header files as found in PERL_SRC or $archlibexp/CORE.
+
+Used by perldepend() in MM_Unix and MM_VMS via _perl_header_files_fragment()
+
+=end private
+
+=cut
+
+sub _perl_header_files {
+ my $self = shift;
+
+ my $header_dir = $self->{PERL_SRC} || $ENV{PERL_SRC} || $self->catdir($Config{archlibexp}, 'CORE');
+ opendir my $dh, $header_dir
+ or die "Failed to opendir '$header_dir' to find header files: $!";
+
+ # we need to use a temporary here as the sort in scalar context would have undefined results.
+ my @perl_headers= sort grep { /\.h\z/ } readdir($dh);
+
+ closedir $dh;
+
+ return @perl_headers;
+}
+
+=begin private
+
+=head3 _perl_header_files_fragment ($o, $separator)
+
+ my $perl_header_files_fragment= $self->_perl_header_files_fragment("/");
+
+return a Makefile fragment which holds the list of perl header files which
+XS code depends on $(PERL_INC), and sets up the dependency for the $(OBJECT) file.
+
+The $separator argument defaults to "". MM_VMS will set it to "" and MM_UNIX to "/"
+in perldepend(). This reason child subclasses need to control this is that in
+VMS the $(PERL_INC) directory will already have delimiters in it, but in
+UNIX $(PERL_INC) will need a slash between it an the filename. Hypothetically
+win32 could use "\\" (but it doesn't need to).
+
+=end private
+
+=cut
+
+sub _perl_header_files_fragment {
+ my ($self, $separator)= @_;
+ $separator ||= "";
+ return join("\\\n",
+ "PERL_HDRS = ",
+ map {
+ sprintf( " \$(PERL_INCDEP)%s%s ", $separator, $_ )
+ } $self->_perl_header_files()
+ ) . "\n\n"
+ . "\$(OBJECT) : \$(PERL_HDRS)\n";
+}
+
+
+=head1 AUTHOR
+
+Michael G Schwern and the denizens of
+makemaker@perl.org with code from ExtUtils::MM_Unix and
+ExtUtils::MM_Win32.
+
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_BeOS.pm b/src/main/perl/lib/ExtUtils/MM_BeOS.pm
new file mode 100644
index 000000000..00175c326
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_BeOS.pm
@@ -0,0 +1,66 @@
+package ExtUtils::MM_BeOS;
+
+use strict;
+use warnings;
+
+=head1 NAME
+
+ExtUtils::MM_BeOS - methods to override UN*X behaviour in ExtUtils::MakeMaker
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MM_BeOS; # Done internally by ExtUtils::MakeMaker if needed
+
+=head1 DESCRIPTION
+
+See L for a documentation of the methods provided
+there. This package overrides the implementation of these methods, not
+the semantics.
+
+=over 4
+
+=cut
+
+use ExtUtils::MakeMaker::Config;
+use File::Spec;
+require ExtUtils::MM_Any;
+require ExtUtils::MM_Unix;
+
+our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+
+=item os_flavor
+
+BeOS is BeOS.
+
+=cut
+
+sub os_flavor {
+ return('BeOS');
+}
+
+=item init_linker
+
+libperl.a equivalent to be linked to dynamic extensions.
+
+=cut
+
+sub init_linker {
+ my($self) = shift;
+
+ $self->{PERL_ARCHIVE} ||=
+ File::Spec->catdir('$(PERL_INC)',$Config{libperl});
+ $self->{PERL_ARCHIVEDEP} ||= '';
+ $self->{PERL_ARCHIVE_AFTER} ||= '';
+ $self->{EXPORT_LIST} ||= '';
+}
+
+=back
+
+=cut
+
+1;
+__END__
+
diff --git a/src/main/perl/lib/ExtUtils/MM_Cygwin.pm b/src/main/perl/lib/ExtUtils/MM_Cygwin.pm
new file mode 100644
index 000000000..6990af6fd
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_Cygwin.pm
@@ -0,0 +1,176 @@
+package ExtUtils::MM_Cygwin;
+
+use strict;
+use warnings;
+
+use ExtUtils::MakeMaker::Config;
+use File::Spec;
+
+require ExtUtils::MM_Unix;
+require ExtUtils::MM_Win32;
+our @ISA = qw( ExtUtils::MM_Unix );
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+
+=head1 NAME
+
+ExtUtils::MM_Cygwin - methods to override UN*X behaviour in ExtUtils::MakeMaker
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MM_Cygwin; # Done internally by ExtUtils::MakeMaker if needed
+
+=head1 DESCRIPTION
+
+See L for a documentation of the methods provided there.
+
+=over 4
+
+=item os_flavor
+
+We're Unix and Cygwin.
+
+=cut
+
+sub os_flavor {
+ return('Unix', 'Cygwin');
+}
+
+=item cflags
+
+if configured for dynamic loading, triggers #define EXT in EXTERN.h
+
+=cut
+
+sub cflags {
+ my($self,$libperl)=@_;
+ return $self->{CFLAGS} if $self->{CFLAGS};
+ return '' unless $self->needs_linking();
+
+ my $base = $self->SUPER::cflags($libperl);
+ foreach (split /\n/, $base) {
+ /^(\S*)\s*=\s*(\S*)$/ and $self->{$1} = $2;
+ };
+ $self->{CCFLAGS} .= " -DUSEIMPORTLIB" if ($Config{useshrplib} eq 'true');
+
+ return $self->{CFLAGS} = qq{
+CCFLAGS = $self->{CCFLAGS}
+OPTIMIZE = $self->{OPTIMIZE}
+PERLTYPE = $self->{PERLTYPE}
+};
+
+}
+
+
+=item replace_manpage_separator
+
+replaces strings '::' with '.' in MAN*POD man page names
+
+=cut
+
+sub replace_manpage_separator {
+ my($self, $man) = @_;
+ $man =~ s{/+}{.}g;
+ return $man;
+}
+
+=item init_linker
+
+points to libperl.a
+
+=cut
+
+sub init_linker {
+ my $self = shift;
+
+ if ($Config{useshrplib} eq 'true') {
+ my $libperl = '$(PERL_INC)' .'/'. "$Config{libperl}";
+ if( "$]" >= 5.006002 ) {
+ $libperl =~ s/(dll\.)?a$/dll.a/;
+ }
+ $self->{PERL_ARCHIVE} = $libperl;
+ } else {
+ $self->{PERL_ARCHIVE} =
+ '$(PERL_INC)' .'/'. ("$Config{libperl}" or "libperl.a");
+ }
+
+ $self->{PERL_ARCHIVEDEP} ||= '';
+ $self->{PERL_ARCHIVE_AFTER} ||= '';
+ $self->{EXPORT_LIST} ||= '';
+}
+
+sub init_others {
+ my $self = shift;
+
+ $self->SUPER::init_others;
+
+ $self->{LDLOADLIBS} ||= $Config{perllibs};
+
+ return;
+}
+
+=item maybe_command
+
+Determine whether a file is native to Cygwin by checking whether it
+resides inside the Cygwin installation (using Windows paths). If so,
+use L to determine if it may be a command.
+Otherwise use the tests from L.
+
+=cut
+
+sub maybe_command {
+ my ($self, $file) = @_;
+
+ my $cygpath = Cygwin::posix_to_win_path('/', 1);
+ my $filepath = Cygwin::posix_to_win_path($file, 1);
+
+ return (substr($filepath,0,length($cygpath)) eq $cygpath)
+ ? $self->SUPER::maybe_command($file) # Unix
+ : ExtUtils::MM_Win32->maybe_command($file); # Win32
+}
+
+=item dynamic_lib
+
+Use the default to produce the *.dll's.
+But for new archdir dll's use the same rebase address if the old exists.
+
+=cut
+
+sub dynamic_lib {
+ my($self, %attribs) = @_;
+ my $s = ExtUtils::MM_Unix::dynamic_lib($self, %attribs);
+ return '' unless $s;
+ return $s unless %{$self->{XS}};
+
+ # do an ephemeral rebase so the new DLL fits to the current rebase map
+ $s .= "\t/bin/find \$\(INST_ARCHLIB\)/auto -xdev -name \\*.$self->{DLEXT} | /bin/rebase -sOT -" if (( $Config{myarchname} eq 'i686-cygwin' ) and not ( exists $ENV{CYGPORT_PACKAGE_VERSION} ));
+ $s;
+}
+
+=item install
+
+Rebase dll's with the global rebase database after installation.
+
+=cut
+
+sub install {
+ my($self, %attribs) = @_;
+ my $s = ExtUtils::MM_Unix::install($self, %attribs);
+ return '' unless $s;
+ return $s unless %{$self->{XS}};
+
+ my $INSTALLDIRS = $self->{INSTALLDIRS};
+ my $INSTALLLIB = $self->{"INSTALL". ($INSTALLDIRS eq 'perl' ? 'ARCHLIB' : uc($INSTALLDIRS)."ARCH")};
+ my $dop = "\$\(DESTDIR\)$INSTALLLIB/auto/";
+ my $dll = "$dop/$self->{FULLEXT}/$self->{BASEEXT}.$self->{DLEXT}";
+ $s =~ s|^(pure_install :: pure_\$\(INSTALLDIRS\)_install\n\t)\$\(NOECHO\) \$\(NOOP\)\n|$1\$(CHMOD) \$(PERM_RWX) $dll\n\t/bin/find $dop -xdev -name \\*.$self->{DLEXT} \| /bin/rebase -sOT -\n|m if (( $Config{myarchname} eq 'i686-cygwin') and not ( exists $ENV{CYGPORT_PACKAGE_VERSION} ));
+ $s;
+}
+
+=back
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_DOS.pm b/src/main/perl/lib/ExtUtils/MM_DOS.pm
new file mode 100644
index 000000000..b2792144a
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_DOS.pm
@@ -0,0 +1,75 @@
+package ExtUtils::MM_DOS;
+
+use strict;
+use warnings;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Any;
+require ExtUtils::MM_Unix;
+our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
+
+
+=head1 NAME
+
+ExtUtils::MM_DOS - DOS specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality
+for DOS.
+
+Unless otherwise stated, it works just like ExtUtils::MM_Unix.
+
+=head2 Overridden methods
+
+=over 4
+
+=item os_flavor
+
+=cut
+
+sub os_flavor {
+ return('DOS');
+}
+
+=item B
+
+Generates Foo__Bar.3 style man page names
+
+=cut
+
+sub replace_manpage_separator {
+ my($self, $man) = @_;
+
+ $man =~ s,/+,__,g;
+ return $man;
+}
+
+=item xs_static_lib_is_xs
+
+=cut
+
+sub xs_static_lib_is_xs {
+ return 1;
+}
+
+=back
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L, L
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_Darwin.pm b/src/main/perl/lib/ExtUtils/MM_Darwin.pm
new file mode 100644
index 000000000..0e8512659
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_Darwin.pm
@@ -0,0 +1,49 @@
+package ExtUtils::MM_Darwin;
+
+use strict;
+use warnings;
+
+BEGIN {
+ require ExtUtils::MM_Unix;
+ our @ISA = qw( ExtUtils::MM_Unix );
+}
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+
+=head1 NAME
+
+ExtUtils::MM_Darwin - special behaviors for OS X
+
+=head1 SYNOPSIS
+
+ For internal MakeMaker use only
+
+=head1 DESCRIPTION
+
+See L or L for documentation on the
+methods overridden here.
+
+=head2 Overridden Methods
+
+=head3 init_dist
+
+Turn off Apple tar's tendency to copy resource forks as "._foo" files.
+
+=cut
+
+sub init_dist {
+ my $self = shift;
+
+ # Thank you, Apple, for breaking tar and then breaking the work around.
+ # 10.4 wants COPY_EXTENDED_ATTRIBUTES_DISABLE while 10.5 wants
+ # COPYFILE_DISABLE. I'm not going to push my luck and instead just
+ # set both.
+ $self->{TAR} ||=
+ 'COPY_EXTENDED_ATTRIBUTES_DISABLE=1 COPYFILE_DISABLE=1 tar';
+
+ $self->SUPER::init_dist(@_);
+}
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_MacOS.pm b/src/main/perl/lib/ExtUtils/MM_MacOS.pm
new file mode 100644
index 000000000..d1b3903bb
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_MacOS.pm
@@ -0,0 +1,35 @@
+package ExtUtils::MM_MacOS;
+
+use strict;
+use warnings;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+sub new {
+ die 'MacOS Classic (MacPerl) is no longer supported by MakeMaker';
+}
+
+=head1 NAME
+
+ExtUtils::MM_MacOS - once produced Makefiles for MacOS Classic
+
+=head1 SYNOPSIS
+
+ # MM_MacOS no longer contains any code. This is just a stub.
+
+=head1 DESCRIPTION
+
+Once upon a time, MakeMaker could produce an approximation of a correct
+Makefile on MacOS Classic (MacPerl). Due to a lack of maintainers, this
+fell out of sync with the rest of MakeMaker and hadn't worked in years.
+Since there's little chance of it being repaired, MacOS Classic is fading
+away, and the code was icky to begin with, the code has been deleted to
+make maintenance easier.
+
+Anyone interested in resurrecting this file should pull the old version
+from the MakeMaker CVS repository and contact makemaker@perl.org.
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_NW5.pm b/src/main/perl/lib/ExtUtils/MM_NW5.pm
new file mode 100644
index 000000000..9195d72b7
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_NW5.pm
@@ -0,0 +1,209 @@
+package ExtUtils::MM_NW5;
+
+=head1 NAME
+
+ExtUtils::MM_NW5 - methods to override UN*X behaviour in ExtUtils::MakeMaker
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MM_NW5; # Done internally by ExtUtils::MakeMaker if needed
+
+=head1 DESCRIPTION
+
+See L for a documentation of the methods provided
+there. This package overrides the implementation of these methods, not
+the semantics.
+
+=over
+
+=cut
+
+use strict;
+use warnings;
+use ExtUtils::MakeMaker::Config;
+use File::Basename;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Win32;
+our @ISA = qw(ExtUtils::MM_Win32);
+
+use ExtUtils::MakeMaker qw(&neatvalue &_sprintf562);
+
+$ENV{EMXSHELL} = 'sh'; # to run `commands`
+
+my $BORLAND = $Config{'cc'} =~ /\bbcc/i;
+my $GCC = $Config{'cc'} =~ /\bgcc/i;
+
+
+=item os_flavor
+
+We're Netware in addition to being Windows.
+
+=cut
+
+sub os_flavor {
+ my $self = shift;
+ return ($self->SUPER::os_flavor, 'Netware');
+}
+
+=item init_platform
+
+Add Netware macros.
+
+LIBPTH, BASE_IMPORT, NLM_VERSION, MPKTOOL, TOOLPATH, BOOT_SYMBOL,
+NLM_SHORT_NAME, INCLUDE, PATH, MM_NW5_REVISION
+
+
+=item platform_constants
+
+Add Netware macros initialized above to the Makefile.
+
+=cut
+
+sub init_platform {
+ my($self) = shift;
+
+ # To get Win32's setup.
+ $self->SUPER::init_platform;
+
+ # incpath is copied to makefile var INCLUDE in constants sub, here just
+ # make it empty
+ my $libpth = $Config{'libpth'};
+ $libpth =~ s( )(;);
+ $self->{'LIBPTH'} = $libpth;
+
+ $self->{'BASE_IMPORT'} = $Config{'base_import'};
+
+ # Additional import file specified from Makefile.pl
+ if($self->{'base_import'}) {
+ $self->{'BASE_IMPORT'} .= ', ' . $self->{'base_import'};
+ }
+
+ $self->{'NLM_VERSION'} = $Config{'nlm_version'};
+ $self->{'MPKTOOL'} = $Config{'mpktool'};
+ $self->{'TOOLPATH'} = $Config{'toolpath'};
+
+ (my $boot = $self->{'NAME'}) =~ s/:/_/g;
+ $self->{'BOOT_SYMBOL'}=$boot;
+
+ # If the final binary name is greater than 8 chars,
+ # truncate it here.
+ if(length($self->{'BASEEXT'}) > 8) {
+ $self->{'NLM_SHORT_NAME'} = substr($self->{'BASEEXT'},0,8);
+ }
+
+ # Get the include path and replace the spaces with ;
+ # Copy this to makefile as INCLUDE = d:\...;d:\;
+ ($self->{INCLUDE} = $Config{'incpath'}) =~ s/([ ]*)-I/;/g;
+
+ # Set the path to CodeWarrior binaries which might not have been set in
+ # any other place
+ $self->{PATH} = '$(PATH);$(TOOLPATH)';
+
+ $self->{MM_NW5_VERSION} = $VERSION;
+}
+
+sub platform_constants {
+ my($self) = shift;
+ my $make_frag = '';
+
+ # Setup Win32's constants.
+ $make_frag .= $self->SUPER::platform_constants;
+
+ foreach my $macro (qw(LIBPTH BASE_IMPORT NLM_VERSION MPKTOOL
+ TOOLPATH BOOT_SYMBOL NLM_SHORT_NAME INCLUDE PATH
+ MM_NW5_VERSION
+ ))
+ {
+ next unless defined $self->{$macro};
+ $make_frag .= "$macro = $self->{$macro}\n";
+ }
+
+ return $make_frag;
+}
+
+=item static_lib_pure_cmd
+
+Defines how to run the archive utility
+
+=cut
+
+sub static_lib_pure_cmd {
+ my ($self, $src) = @_;
+ $src =~ s/(\$\(\w+)(\))/$1:^"+"$2/g if $BORLAND;
+ sprintf qq{\t\$(AR) %s\n}, ($BORLAND ? '$@ ' . $src
+ : ($GCC ? '-ru $@ ' . $src
+ : '-type library -o $@ ' . $src));
+}
+
+=item xs_static_lib_is_xs
+
+=cut
+
+sub xs_static_lib_is_xs {
+ return 1;
+}
+
+=item dynamic_lib
+
+Override of utility methods for OS-specific work.
+
+=cut
+
+sub xs_make_dynamic_lib {
+ my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
+ my @m;
+ # Taking care of long names like FileHandle, ByteLoader, SDBM_File etc
+ if ($to =~ /^\$/) {
+ if ($self->{NLM_SHORT_NAME}) {
+ # deal with shortnames
+ my $newto = q{$(INST_AUTODIR)\\$(NLM_SHORT_NAME).$(DLEXT)};
+ push @m, "$to: $newto\n\n";
+ $to = $newto;
+ }
+ } else {
+ my ($v, $d, $f) = File::Spec->splitpath($to);
+ # relies on $f having a literal "." in it, unlike for $(OBJ_EXT)
+ if ($f =~ /[^\.]{9}\./) {
+ # 9+ chars before '.', need to shorten
+ $f = substr $f, 0, 8;
+ }
+ my $newto = File::Spec->catpath($v, $d, $f);
+ push @m, "$to: $newto\n\n";
+ $to = $newto;
+ }
+ # bits below should be in dlsyms, not here
+ # 1 2 3 4
+ push @m, _sprintf562 <<'MAKE_FRAG', $to, $from, $todir, $exportlist;
+# Create xdc data for an MT safe NLM in case of mpk build
+%1$s: %2$s $(MYEXTLIB) $(BOOTSTRAP) %3$s$(DFSEP).exists
+ $(NOECHO) $(ECHO) Export boot_$(BOOT_SYMBOL) > %4$s
+ $(NOECHO) $(ECHO) $(BASE_IMPORT) >> %4$s
+ $(NOECHO) $(ECHO) Import @$(PERL_INC)\perl.imp >> %4$s
+MAKE_FRAG
+ if ( $self->{CCFLAGS} =~ m/ -DMPK_ON /) {
+ (my $xdc = $exportlist) =~ s#def\z#xdc#;
+ $xdc = '$(BASEEXT).xdc';
+ push @m, sprintf <<'MAKE_FRAG', $xdc, $exportlist;
+ $(MPKTOOL) $(XDCFLAGS) %s
+ $(NOECHO) $(ECHO) xdcdata $(BASEEXT).xdc >> %s
+MAKE_FRAG
+ }
+ # Reconstruct the X.Y.Z version.
+ my $version = join '.', map { sprintf "%d", $_ }
+ "$]" =~ /(\d)\.(\d{3})(\d{2})/;
+ push @m, sprintf <<'EOF', $from, $version, $to, $exportlist;
+ $(LD) $(LDFLAGS) %s -desc "Perl %s Extension ($(BASEEXT)) XS_VERSION: $(XS_VERSION)" -nlmversion $(NLM_VERSION) -o %s $(MYEXTLIB) $(PERL_INC)\Main.lib -commandfile %s
+ $(CHMOD) 755 $@
+EOF
+ join '', @m;
+}
+
+1;
+__END__
+
+=back
+
+=cut
diff --git a/src/main/perl/lib/ExtUtils/MM_OS2.pm b/src/main/perl/lib/ExtUtils/MM_OS2.pm
new file mode 100644
index 000000000..bea9905f7
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_OS2.pm
@@ -0,0 +1,147 @@
+package ExtUtils::MM_OS2;
+
+use strict;
+use warnings;
+
+use ExtUtils::MakeMaker qw(neatvalue);
+use File::Spec;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Any;
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Any ExtUtils::MM_Unix);
+
+=pod
+
+=head1 NAME
+
+ExtUtils::MM_OS2 - methods to override UN*X behaviour in ExtUtils::MakeMaker
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MM_OS2; # Done internally by ExtUtils::MakeMaker if needed
+
+=head1 DESCRIPTION
+
+See L for a documentation of the methods provided
+there. This package overrides the implementation of these methods, not
+the semantics.
+
+=head1 METHODS
+
+=over 4
+
+=item init_dist
+
+Define TO_UNIX to convert OS2 linefeeds to Unix style.
+
+=cut
+
+sub init_dist {
+ my($self) = @_;
+
+ $self->{TO_UNIX} ||= <<'MAKE_TEXT';
+$(NOECHO) $(TEST_F) tmp.zip && $(RM_F) tmp.zip; $(ZIP) -ll -mr tmp.zip $(DISTVNAME) && unzip -o tmp.zip && $(RM_F) tmp.zip
+MAKE_TEXT
+
+ $self->SUPER::init_dist;
+}
+
+sub dlsyms {
+ my($self,%attribs) = @_;
+ if ($self->{IMPORTS} && %{$self->{IMPORTS}}) {
+ # Make import files (needed for static build)
+ -d 'tmp_imp' or mkdir 'tmp_imp', 0777 or die "Can't mkdir tmp_imp";
+ open my $imp, '>', 'tmpimp.imp' or die "Can't open tmpimp.imp";
+ foreach my $name (sort keys %{$self->{IMPORTS}}) {
+ my $exp = $self->{IMPORTS}->{$name};
+ my ($lib, $id) = ($exp =~ /(.*)\.(.*)/) or die "Malformed IMPORT `$exp'";
+ print $imp "$name $lib $id ?\n";
+ }
+ close $imp or die "Can't close tmpimp.imp";
+ # print "emximp -o tmpimp$Config::Config{lib_ext} tmpimp.imp\n";
+ system "emximp -o tmpimp$Config::Config{lib_ext} tmpimp.imp"
+ and die "Cannot make import library: $!, \$?=$?";
+ # May be running under miniperl, so have no glob...
+ eval { unlink ; 1 } or system "rm tmp_imp/*";
+ system "cd tmp_imp; $Config::Config{ar} x ../tmpimp$Config::Config{lib_ext}"
+ and die "Cannot extract import objects: $!, \$?=$?";
+ }
+ return '' if $self->{SKIPHASH}{'dynamic'};
+ $self->xs_dlsyms_iterator(\%attribs);
+}
+
+sub xs_dlsyms_ext {
+ '.def';
+}
+
+sub xs_dlsyms_extra {
+ join '', map { qq{, "$_" => "\$($_)"} } qw(VERSION DISTNAME INSTALLDIRS);
+}
+
+sub static_lib_pure_cmd {
+ my($self) = @_;
+ my $old = $self->SUPER::static_lib_pure_cmd;
+ return $old unless $self->{IMPORTS} && %{$self->{IMPORTS}};
+ $old . <<'EOC';
+ $(AR) $(AR_STATIC_ARGS) "$@" tmp_imp/*
+ $(RANLIB) "$@"
+EOC
+}
+
+sub replace_manpage_separator {
+ my($self,$man) = @_;
+ $man =~ s,/+,.,g;
+ $man;
+}
+
+sub maybe_command {
+ my($self,$file) = @_;
+ $file =~ s,[/\\]+,/,g;
+ return $file if -x $file && ! -d _;
+ return "$file.exe" if -x "$file.exe" && ! -d _;
+ return "$file.cmd" if -x "$file.cmd" && ! -d _;
+ return;
+}
+
+=item init_linker
+
+=cut
+
+sub init_linker {
+ my $self = shift;
+
+ $self->{PERL_ARCHIVE} = "\$(PERL_INC)/libperl\$(LIB_EXT)";
+
+ $self->{PERL_ARCHIVEDEP} ||= '';
+ $self->{PERL_ARCHIVE_AFTER} = $OS2::is_aout
+ ? ''
+ : '$(PERL_INC)/libperl_override$(LIB_EXT)';
+ $self->{EXPORT_LIST} = '$(BASEEXT).def';
+}
+
+=item os_flavor
+
+OS/2 is OS/2
+
+=cut
+
+sub os_flavor {
+ return('OS/2');
+}
+
+=item xs_static_lib_is_xs
+
+=cut
+
+sub xs_static_lib_is_xs {
+ return 1;
+}
+
+=back
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_OS390.pm b/src/main/perl/lib/ExtUtils/MM_OS390.pm
new file mode 100644
index 000000000..3171106a0
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_OS390.pm
@@ -0,0 +1,86 @@
+package ExtUtils::MM_OS390;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+use ExtUtils::MakeMaker::Config;
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Unix);
+
+=head1 NAME
+
+ExtUtils::MM_OS390 - OS390 specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality for
+OS390.
+
+Unless otherwise stated it works just like ExtUtils::MM_Unix.
+
+=head2 Overriden methods
+
+=over
+
+=item xs_make_dynamic_lib
+
+Defines the recipes for the C section.
+
+=cut
+
+sub xs_make_dynamic_lib {
+ my ($self, $attribs, $object, $to, $todir, $ldfrom, $exportlist, $dlsyms) = @_;
+ $exportlist = '' if $exportlist ne '$(EXPORT_LIST)';
+ my $armaybe = $self->_xs_armaybe($attribs);
+ my @m = sprintf '%s : %s $(MYEXTLIB) %s$(DFSEP).exists %s $(PERL_ARCHIVEDEP) $(PERL_ARCHIVE_AFTER) $(INST_DYNAMIC_DEP) %s'."\n", $to, $object, $todir, $exportlist, ($dlsyms || '');
+ my $dlsyms_arg = $self->xs_dlsyms_arg($dlsyms);
+ if ($armaybe ne ':'){
+ $ldfrom = 'tmp$(LIB_EXT)';
+ push(@m," \$(ARMAYBE) cr $ldfrom $object\n");
+ push(@m," \$(RANLIB) $ldfrom\n");
+ }
+
+ # For example in AIX the shared objects/libraries from previous builds
+ # linger quite a while in the shared dynalinker cache even when nobody
+ # is using them. This is painful if one for instance tries to restart
+ # a failed build because the link command will fail unnecessarily 'cos
+ # the shared object/library is 'busy'.
+ push(@m," \$(RM_F) \$\@\n");
+
+ my $libs = '$(LDLOADLIBS)';
+
+ my $ld_run_path_shell = "";
+ if ($self->{LD_RUN_PATH} ne "") {
+ $ld_run_path_shell = 'LD_RUN_PATH="$(LD_RUN_PATH)" ';
+ }
+
+ push @m, sprintf <<'MAKE', $ld_run_path_shell, $self->xs_obj_opt('$@'), $dlsyms_arg, $ldfrom, $libs, $exportlist;
+ %s$(LD) %s $(LDDLFLAGS) %s $(OTHERLDFLAGS) %s $(MYEXTLIB) \
+ $(PERL_ARCHIVE) %s $(PERL_ARCHIVE_AFTER) %s \
+ $(INST_DYNAMIC_FIX)
+ $(CHMOD) $(PERM_RWX) $@
+MAKE
+ join '', @m;
+}
+
+1;
+
+=back
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L
+
+=cut
+__END__
diff --git a/src/main/perl/lib/ExtUtils/MM_PerlOnJava.pm b/src/main/perl/lib/ExtUtils/MM_PerlOnJava.pm
index 8ef7b627c..1da6b30e7 100644
--- a/src/main/perl/lib/ExtUtils/MM_PerlOnJava.pm
+++ b/src/main/perl/lib/ExtUtils/MM_PerlOnJava.pm
@@ -20,6 +20,19 @@ our @ISA = qw(ExtUtils::MM_Unix);
our $VERSION = '7.78';
$VERSION =~ tr/_//d;
+# Override init_main to set PerlOnJava-specific defaults
+sub init_main {
+ my $self = shift;
+ $self->SUPER::init_main(@_);
+
+ # Don't try to write perllocal.pod or .packlist to jar:PERL5LIB
+ # (which is not a real filesystem path)
+ $self->{NO_PERLLOCAL} = 1;
+ $self->{NO_PACKLIST} = 1;
+
+ return;
+}
+
# Installation base directory
sub _perlonjava_lib {
return $ENV{PERLONJAVA_LIB}
@@ -78,6 +91,7 @@ sub init_xs {
}
# Override: Simplified test target
+# Sets PERL5LIB to include blib/lib so test subprocesses can find the module
sub test {
my($self, %attribs) = @_;
@@ -88,14 +102,14 @@ sub test {
return '' unless $tests;
- my $perl = $self->{FULLPERL} || $self->{PERL} || '$(PERL)';
-
+ # Set PERL5LIB to add blib/lib and blib/arch to @INC for test subprocesses
+ # Test::Harness runs each test file as a subprocess, so we need PERL5LIB
return <<"MAKE_FRAG";
test :: pure_all
- $perl -e 'use Test::Harness; runtests(glob(q{$tests}))'
+ PERL5LIB="\$(INST_LIB):\$(INST_ARCHLIB):\$\$PERL5LIB" \$(FULLPERL) -e 'use Test::Harness; runtests(glob(q{$tests}))'
test_dynamic :: pure_all
- $perl -e 'use Test::Harness; runtests(glob(q{$tests}))'
+ PERL5LIB="\$(INST_LIB):\$(INST_ARCHLIB):\$\$PERL5LIB" \$(FULLPERL) -e 'use Test::Harness; runtests(glob(q{$tests}))'
test_static ::
\@echo "No static tests for PerlOnJava"
diff --git a/src/main/perl/lib/ExtUtils/MM_QNX.pm b/src/main/perl/lib/ExtUtils/MM_QNX.pm
new file mode 100644
index 000000000..41acfbaee
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_QNX.pm
@@ -0,0 +1,59 @@
+package ExtUtils::MM_QNX;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Unix);
+
+
+=head1 NAME
+
+ExtUtils::MM_QNX - QNX specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality for
+QNX.
+
+Unless otherwise stated it works just like ExtUtils::MM_Unix.
+
+=head2 Overridden methods
+
+=head3 extra_clean_files
+
+Add .err files corresponding to each .c file.
+
+=cut
+
+sub extra_clean_files {
+ my $self = shift;
+
+ my @errfiles = @{$self->{C}};
+ for ( @errfiles ) {
+ s/.c$/.err/;
+ }
+
+ return( @errfiles, 'perlmain.err' );
+}
+
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_UWIN.pm b/src/main/perl/lib/ExtUtils/MM_UWIN.pm
new file mode 100644
index 000000000..2d129e6ed
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_UWIN.pm
@@ -0,0 +1,66 @@
+package ExtUtils::MM_UWIN;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Unix);
+
+
+=head1 NAME
+
+ExtUtils::MM_UWIN - U/WIN specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality for
+the AT&T U/WIN UNIX on Windows environment.
+
+Unless otherwise stated it works just like ExtUtils::MM_Unix.
+
+=head2 Overridden methods
+
+=over 4
+
+=item os_flavor
+
+In addition to being Unix, we're U/WIN.
+
+=cut
+
+sub os_flavor {
+ return('Unix', 'U/WIN');
+}
+
+
+=item B
+
+=cut
+
+sub replace_manpage_separator {
+ my($self, $man) = @_;
+
+ $man =~ s,/+,.,g;
+ return $man;
+}
+
+=back
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L, L
+
+=cut
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_Unix.pm b/src/main/perl/lib/ExtUtils/MM_Unix.pm
index f738d4b03..9d406b87d 100644
--- a/src/main/perl/lib/ExtUtils/MM_Unix.pm
+++ b/src/main/perl/lib/ExtUtils/MM_Unix.pm
@@ -2,7 +2,7 @@ package ExtUtils::MM_Unix;
use strict;
use warnings;
-our $VERSION = '7.70_perlonjava';
+our $VERSION = '7.78_perlonjava';
# MM_Unix provides Unix-specific methods for ExtUtils::MakeMaker.
# In PerlOnJava, we only implement the methods needed by CPAN.pm.
@@ -49,27 +49,35 @@ sub parse_version {
}
# get_version - helper for parse_version
-# Based on the standard ExtUtils::MakeMaker implementation
+# Simplified implementation that avoids package block issues
sub get_version {
my ($self, $parsefile, $sigil, $name) = @_;
my $line = $_; # from the while() loop in parse_version
-
# Clean up taint mode markers
- $line = $1 if $line =~ /^(.+)/s;
+ $line = $1 if $line =~ m{^(.+)}s;
- # Use eval to both set and retrieve the version in one step
- # This avoids issues with symbolic dereferencing in JAR-loaded modules
+ # Directly extract version from common patterns
+ # Pattern 1: $VERSION = '1.23' or $VERSION = "1.23"
+ if ($line =~ /\$VERSION\s*=\s*['"]([^'"]+)['"]/) {
+ return $1;
+ }
+ # Pattern 2: $VERSION = 1.23 (bare number)
+ if ($line =~ /\$VERSION\s*=\s*([\d._]+)/) {
+ return $1;
+ }
+ # Pattern 3: version->new('v1.2.3') or version->declare('v1.2.3')
+ if ($line =~ /version->(?:new|declare)\s*\(\s*['"]([^'"]+)['"]/) {
+ return $1;
+ }
+ # Fallback: try eval (may not work in all contexts)
{
- package ExtUtils::MakeMaker::_version;
- undef *version;
- eval { require version; version->import };
no strict;
no warnings;
- local *{$name};
- eval $line; ## no critic
- # Use eval to retrieve the value - more reliable than ${$name}
- return eval "\$$name"; ## no critic
+ local $ExtUtils::MakeMaker::_version::VERSION;
+ eval "package ExtUtils::MakeMaker::_version; $line"; ## no critic
+ return $ExtUtils::MakeMaker::_version::VERSION if defined $ExtUtils::MakeMaker::_version::VERSION;
}
+ return;
}
# maybe_command - check if a file is an executable command (Unix version)
diff --git a/src/main/perl/lib/ExtUtils/MM_VMS.pm b/src/main/perl/lib/ExtUtils/MM_VMS.pm
new file mode 100644
index 000000000..5ba22e608
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_VMS.pm
@@ -0,0 +1,2284 @@
+package ExtUtils::MM_VMS;
+
+use strict;
+use warnings;
+
+use ExtUtils::MakeMaker::Config;
+require Exporter;
+
+BEGIN {
+ # so we can compile the thing on non-VMS platforms.
+ if( $^O eq 'VMS' ) {
+ require VMS::Filespec;
+ VMS::Filespec->import;
+ }
+}
+
+use File::Basename;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Any;
+require ExtUtils::MM_Unix;
+our @ISA = qw( ExtUtils::MM_Any ExtUtils::MM_Unix );
+
+use ExtUtils::MakeMaker qw($Verbose neatvalue _sprintf562);
+our $Revision = $ExtUtils::MakeMaker::Revision;
+
+
+=head1 NAME
+
+ExtUtils::MM_VMS - methods to override UN*X behaviour in ExtUtils::MakeMaker
+
+=head1 SYNOPSIS
+
+ Do not use this directly.
+ Instead, use ExtUtils::MM and it will figure out which MM_*
+ class to use for you.
+
+=head1 DESCRIPTION
+
+See L for a documentation of the methods provided
+there. This package overrides the implementation of these methods, not
+the semantics.
+
+=head2 Methods always loaded
+
+=over 4
+
+=item wraplist
+
+Converts a list into a string wrapped at approximately 80 columns.
+
+=cut
+
+sub wraplist {
+ my($self) = shift;
+ my($line,$hlen) = ('',0);
+
+ foreach my $word (@_) {
+ # Perl bug -- seems to occasionally insert extra elements when
+ # traversing array (scalar(@array) doesn't show them, but
+ # foreach(@array) does) (5.00307)
+ next unless $word =~ /\w/;
+ $line .= ' ' if length($line);
+ if ($hlen > 80) { $line .= "\\\n\t"; $hlen = 0; }
+ $line .= $word;
+ $hlen += length($word) + 2;
+ }
+ $line;
+}
+
+
+# This isn't really an override. It's just here because ExtUtils::MM_VMS
+# appears in @MM::ISA before ExtUtils::Liblist::Kid, so if there isn't an ext()
+# in MM_VMS, then AUTOLOAD is called, and bad things happen. So, we just
+# mimic inheritance here and hand off to ExtUtils::Liblist::Kid.
+# XXX This hackery will die soon. --Schwern
+sub ext {
+ require ExtUtils::Liblist::Kid;
+ goto &ExtUtils::Liblist::Kid::ext;
+}
+
+=back
+
+=head2 Methods
+
+Those methods which override default MM_Unix methods are marked
+"(override)", while methods unique to MM_VMS are marked "(specific)".
+For overridden methods, documentation is limited to an explanation
+of why this method overrides the MM_Unix method; see the L
+documentation for more details.
+
+=over 4
+
+=item guess_name (override)
+
+Try to determine name of extension being built. We begin with the name
+of the current directory. Since VMS filenames are case-insensitive,
+however, we look for a F<.pm> file whose name matches that of the current
+directory (presumably the 'main' F<.pm> file for this extension), and try
+to find a C statement from which to obtain the Mixed::Case
+package name.
+
+=cut
+
+sub guess_name {
+ my($self) = @_;
+ my($defname,$defpm,@pm,%xs);
+ local *PM;
+
+ $defname = basename(fileify($ENV{'DEFAULT'}));
+ $defname =~ s![\d\-_]*\.dir.*$!!; # Clip off .dir;1 suffix, and package version
+ $defpm = $defname;
+ # Fallback in case for some reason a user has copied the files for an
+ # extension into a working directory whose name doesn't reflect the
+ # extension's name. We'll use the name of a unique .pm file, or the
+ # first .pm file with a matching .xs file.
+ if (not -e "${defpm}.pm") {
+ @pm = glob('*.pm');
+ s/.pm$// for @pm;
+ if (@pm == 1) { ($defpm = $pm[0]) =~ s/.pm$//; }
+ elsif (@pm) {
+ %xs = map { s/.xs$//; ($_,1) } glob('*.xs'); ## no critic
+ if (keys %xs) {
+ foreach my $pm (@pm) {
+ $defpm = $pm, last if exists $xs{$pm};
+ }
+ }
+ }
+ }
+ if (open(my $pm, '<', "${defpm}.pm")){
+ while (<$pm>) {
+ if (/^\s*package\s+([^;]+)/i) {
+ $defname = $1;
+ last;
+ }
+ }
+ print "Warning (non-fatal): Couldn't find package name in ${defpm}.pm;\n\t",
+ "defaulting package name to $defname\n"
+ if eof($pm);
+ close $pm;
+ }
+ else {
+ print "Warning (non-fatal): Couldn't find ${defpm}.pm;\n\t",
+ "defaulting package name to $defname\n";
+ }
+ $defname =~ s#[\d.\-_]+$##;
+ $defname;
+}
+
+=item find_perl (override)
+
+Use VMS file specification syntax and CLI commands to find and
+invoke Perl images.
+
+=cut
+
+sub find_perl {
+ my($self, $ver, $names, $dirs, $trace) = @_;
+ my($vmsfile,@sdirs,@snames,@cand);
+ my($rslt);
+ my($inabs) = 0;
+ local *TCF;
+
+ if( $self->{PERL_CORE} ) {
+ # Check in relative directories first, so we pick up the current
+ # version of Perl if we're running MakeMaker as part of the main build.
+ @sdirs = sort { my($absa) = $self->file_name_is_absolute($a);
+ my($absb) = $self->file_name_is_absolute($b);
+ if ($absa && $absb) { return $a cmp $b }
+ else { return $absa ? 1 : ($absb ? -1 : ($a cmp $b)); }
+ } @$dirs;
+ # Check miniperl before perl, and check names likely to contain
+ # version numbers before "generic" names, so we pick up an
+ # executable that's less likely to be from an old installation.
+ @snames = sort { my($ba) = $a =~ m!([^:>\]/]+)$!; # basename
+ my($bb) = $b =~ m!([^:>\]/]+)$!;
+ my($ahasdir) = (length($a) - length($ba) > 0);
+ my($bhasdir) = (length($b) - length($bb) > 0);
+ if ($ahasdir and not $bhasdir) { return 1; }
+ elsif ($bhasdir and not $ahasdir) { return -1; }
+ else { $bb =~ /\d/ <=> $ba =~ /\d/
+ or substr($ba,0,1) cmp substr($bb,0,1)
+ or length($bb) <=> length($ba) } } @$names;
+ }
+ else {
+ @sdirs = @$dirs;
+ @snames = @$names;
+ }
+
+ # Image names containing Perl version use '_' instead of '.' under VMS
+ s/\.(\d+)$/_$1/ for @snames;
+ if ($trace >= 2){
+ print "Looking for perl $ver by these names:\n";
+ print "\t@snames,\n";
+ print "in these dirs:\n";
+ print "\t@sdirs\n";
+ }
+ foreach my $dir (@sdirs){
+ next unless defined $dir; # $self->{PERL_SRC} may be undefined
+ $inabs++ if $self->file_name_is_absolute($dir);
+ if ($inabs == 1) {
+ # We've covered relative dirs; everything else is an absolute
+ # dir (probably an installed location). First, we'll try
+ # potential command names, to see whether we can avoid a long
+ # MCR expression.
+ foreach my $name (@snames) {
+ push(@cand,$name) if $name =~ /^[\w\-\$]+$/;
+ }
+ $inabs++; # Should happen above in next $dir, but just in case...
+ }
+ foreach my $name (@snames){
+ push @cand, ($name !~ m![/:>\]]!) ? $self->catfile($dir,$name)
+ : $self->fixpath($name,0);
+ }
+ }
+ foreach my $name (@cand) {
+ print "Checking $name\n" if $trace >= 2;
+ # If it looks like a potential command, try it without the MCR
+ if ($name =~ /^[\w\-\$]+$/) {
+ open(my $tcf, ">", "temp_mmvms.com")
+ or die('unable to open temp file');
+ print $tcf "\$ set message/nofacil/nosever/noident/notext\n";
+ print $tcf "\$ $name -e \"require $ver; print \"\"VER_OK\\n\"\"\"\n";
+ close $tcf;
+ $rslt = `\@temp_mmvms.com` ;
+ unlink('temp_mmvms.com');
+ if ($rslt =~ /VER_OK/) {
+ print "Using PERL=$name\n" if $trace;
+ return $name;
+ }
+ }
+ next unless $vmsfile = $self->maybe_command($name);
+ $vmsfile =~ s/;[\d\-]*$//; # Clip off version number; we can use a newer version as well
+ print "Executing $vmsfile\n" if ($trace >= 2);
+ open(my $tcf, '>', "temp_mmvms.com")
+ or die('unable to open temp file');
+ print $tcf "\$ set message/nofacil/nosever/noident/notext\n";
+ print $tcf "\$ mcr $vmsfile -e \"require $ver; print \"\"VER_OK\\n\"\"\" \n";
+ close $tcf;
+ $rslt = `\@temp_mmvms.com`;
+ unlink('temp_mmvms.com');
+ if ($rslt =~ /VER_OK/) {
+ print "Using PERL=MCR $vmsfile\n" if $trace;
+ return "MCR $vmsfile";
+ }
+ }
+ print "Unable to find a perl $ver (by these names: @$names, in these dirs: @$dirs)\n";
+ 0; # false and not empty
+}
+
+=item _fixin_replace_shebang (override)
+
+Helper routine for L<< MM->fixin()|ExtUtils::MM_Unix/fixin >>, overridden
+because there's no such thing as an
+actual shebang line that will be interpreted by the shell, so we just prepend
+$Config{startperl} and preserve the shebang line argument for any switches it
+may contain.
+
+=cut
+
+sub _fixin_replace_shebang {
+ my ( $self, $file, $line ) = @_;
+
+ my ( undef, $arg ) = split ' ', $line, 2;
+ $arg ||= '';
+
+ return $Config{startperl} . "\n" . $Config{sharpbang} . "perl $arg\n";
+}
+
+=item maybe_command (override)
+
+Follows VMS naming conventions for executable files.
+If the name passed in doesn't exactly match an executable file,
+appends F<.Exe> (or equivalent) to check for executable image, and F<.Com>
+to check for DCL procedure. If this fails, checks directories in DCL$PATH
+and finally F for an executable file having the name specified,
+with or without the F<.Exe>-equivalent suffix.
+
+=cut
+
+sub maybe_command {
+ my($self,$file) = @_;
+ return $file if -x $file && ! -d _;
+ my(@dirs) = ('');
+ my(@exts) = ('',$Config{'exe_ext'},'.exe','.com');
+
+ if ($file !~ m![/:>\]]!) {
+ for (my $i = 0; defined $ENV{"DCL\$PATH;$i"}; $i++) {
+ my $dir = $ENV{"DCL\$PATH;$i"};
+ $dir .= ':' unless $dir =~ m%[\]:]$%;
+ push(@dirs,$dir);
+ }
+ push(@dirs,'Sys$System:');
+ foreach my $dir (@dirs) {
+ my $sysfile = "$dir$file";
+ foreach my $ext (@exts) {
+ return $file if -x "$sysfile$ext" && ! -d _;
+ }
+ }
+ }
+ return 0;
+}
+
+
+=item pasthru (override)
+
+The list of macro definitions to be passed through must be specified using
+the /MACRO qualifier and must not add another /DEFINE qualifier. We prepend
+our own comma here to the contents of $(PASTHRU_DEFINE) because it is often
+empty and a comma always present in CCFLAGS would generate a missing
+qualifier value error.
+
+=cut
+
+sub pasthru {
+ my($self) = shift;
+ my $pasthru = $self->SUPER::pasthru;
+ $pasthru =~ s|(PASTHRU\s*=\s*)|$1/MACRO=(|;
+ $pasthru =~ s|\n\z|)\n|m;
+ $pasthru =~ s|/defi?n?e?=\(?([^\),]+)\)?|,$1|ig;
+
+ return $pasthru;
+}
+
+
+=item pm_to_blib (override)
+
+VMS wants a dot in every file so we can't have one called 'pm_to_blib',
+it becomes 'pm_to_blib.' and MMS/K isn't smart enough to know that when
+you have a target called 'pm_to_blib' it should look for 'pm_to_blib.'.
+
+So in VMS its pm_to_blib.ts.
+
+=cut
+
+sub pm_to_blib {
+ my $self = shift;
+
+ my $make = $self->SUPER::pm_to_blib;
+
+ $make =~ s{^pm_to_blib :}{pm_to_blib.ts :}m;
+ $make =~ s{\$\(TOUCH\) pm_to_blib}{\$(TOUCH) pm_to_blib.ts};
+
+ $make = <<'MAKE' . $make;
+# Dummy target to match Unix target name; we use pm_to_blib.ts as
+# timestamp file to avoid repeated invocations under VMS
+pm_to_blib : pm_to_blib.ts
+ $(NOECHO) $(NOOP)
+
+MAKE
+
+ return $make;
+}
+
+
+=item perl_script (override)
+
+If name passed in doesn't specify a readable file, appends F<.com> or
+F<.pl> and tries again, since it's customary to have file types on all files
+under VMS.
+
+=cut
+
+sub perl_script {
+ my($self,$file) = @_;
+ return $file if -r $file && ! -d _;
+ return "$file.com" if -r "$file.com";
+ return "$file.pl" if -r "$file.pl";
+ return '';
+}
+
+
+=item replace_manpage_separator
+
+Use as separator a character which is legal in a VMS-syntax file name.
+
+=cut
+
+sub replace_manpage_separator {
+ my($self,$man) = @_;
+ $man = unixify($man);
+ $man =~ s#/+#__#g;
+ $man;
+}
+
+=item init_DEST
+
+(override) Because of the difficulty concatenating VMS filepaths we
+must pre-expand the DEST* variables.
+
+=cut
+
+sub init_DEST {
+ my $self = shift;
+
+ $self->SUPER::init_DEST;
+
+ # Expand DEST variables.
+ foreach my $var ($self->installvars) {
+ my $destvar = 'DESTINSTALL'.$var;
+ $self->{$destvar} = $self->eliminate_macros($self->{$destvar});
+ }
+}
+
+
+=item init_DIRFILESEP
+
+No separator between a directory path and a filename on VMS.
+
+=cut
+
+sub init_DIRFILESEP {
+ my($self) = shift;
+
+ $self->{DIRFILESEP} = '';
+ return 1;
+}
+
+
+=item init_main (override)
+
+
+=cut
+
+sub init_main {
+ my($self) = shift;
+
+ $self->SUPER::init_main;
+
+ $self->{DEFINE} ||= '';
+ if ($self->{DEFINE} ne '') {
+ my(@terms) = split(/\s+/,$self->{DEFINE});
+ my(@defs,@udefs);
+ foreach my $def (@terms) {
+ next unless $def;
+ my $targ = \@defs;
+ if ($def =~ s/^-([DU])//) { # If it was a Unix-style definition
+ $targ = \@udefs if $1 eq 'U';
+ $def =~ s/='(.*)'$/=$1/; # then remove shell-protection ''
+ $def =~ s/^'(.*)'$/$1/; # from entire term or argument
+ }
+ if ($def =~ /=/) {
+ $def =~ s/"/""/g; # Protect existing " from DCL
+ $def = qq["$def"]; # and quote to prevent parsing of =
+ }
+ push @$targ, $def;
+ }
+
+ $self->{DEFINE} = '';
+ if (@defs) {
+ $self->{DEFINE} = '/Define=(' . join(',',@defs) . ')';
+ }
+ if (@udefs) {
+ $self->{DEFINE} .= '/Undef=(' . join(',',@udefs) . ')';
+ }
+ }
+}
+
+=item init_tools (override)
+
+Provide VMS-specific forms of various utility commands.
+
+Sets DEV_NULL to nothing because I don't know how to do it on VMS.
+
+Changes EQUALIZE_TIMESTAMP to set revision date of target file to
+one second later than source file, since MMK interprets precisely
+equal revision dates for a source and target file as a sign that the
+target needs to be updated.
+
+=cut
+
+sub init_tools {
+ my($self) = @_;
+
+ $self->{NOOP} = 'Continue';
+ $self->{NOECHO} ||= '@ ';
+
+ $self->{MAKEFILE} ||= $self->{FIRST_MAKEFILE} || 'Descrip.MMS';
+ $self->{FIRST_MAKEFILE} ||= $self->{MAKEFILE};
+ $self->{MAKE_APERL_FILE} ||= 'Makeaperl.MMS';
+ $self->{MAKEFILE_OLD} ||= $self->eliminate_macros('$(FIRST_MAKEFILE)_old');
+#
+# If an extension is not specified, then MMS/MMK assumes an
+# an extension of .MMS. If there really is no extension,
+# then a trailing "." needs to be appended to specify a
+# a null extension.
+#
+ $self->{MAKEFILE} .= '.' unless $self->{MAKEFILE} =~ m/\./;
+ $self->{FIRST_MAKEFILE} .= '.' unless $self->{FIRST_MAKEFILE} =~ m/\./;
+ $self->{MAKE_APERL_FILE} .= '.' unless $self->{MAKE_APERL_FILE} =~ m/\./;
+ $self->{MAKEFILE_OLD} .= '.' unless $self->{MAKEFILE_OLD} =~ m/\./;
+
+ $self->{MACROSTART} ||= '/Macro=(';
+ $self->{MACROEND} ||= ')';
+ $self->{USEMAKEFILE} ||= '/Descrip=';
+
+ $self->{EQUALIZE_TIMESTAMP} ||= '$(ABSPERLRUN) -we "open F,qq{>>$ARGV[1]};close F;utime(0,(stat($ARGV[0]))[9]+1,$ARGV[1])"';
+
+ $self->{MOD_INSTALL} ||=
+ $self->oneliner(<<'CODE', ['-MExtUtils::Install']);
+install([ from_to => {split('\|', )}, verbose => '$(VERBINST)', uninstall_shadows => '$(UNINST)', dir_mode => '$(PERM_DIR)' ]);
+CODE
+
+ $self->{UMASK_NULL} = '! ';
+
+ $self->SUPER::init_tools;
+
+ # Use the default shell
+ $self->{SHELL} ||= 'Posix';
+
+ # Redirection on VMS goes before the command, not after as on Unix.
+ # $(DEV_NULL) is used once and its not worth going nuts over making
+ # it work. However, Unix's DEV_NULL is quite wrong for VMS.
+ $self->{DEV_NULL} = '';
+
+ return;
+}
+
+=item init_platform (override)
+
+Add PERL_VMS, MM_VMS_REVISION and MM_VMS_VERSION.
+
+MM_VMS_REVISION is for backwards compatibility before MM_VMS had a
+$VERSION.
+
+=cut
+
+sub init_platform {
+ my($self) = shift;
+
+ $self->{MM_VMS_REVISION} = $Revision;
+ $self->{MM_VMS_VERSION} = $VERSION;
+ $self->{PERL_VMS} = $self->catdir($self->{PERL_SRC}, 'VMS')
+ if $self->{PERL_SRC};
+}
+
+
+=item platform_constants
+
+=cut
+
+sub platform_constants {
+ my($self) = shift;
+ my $make_frag = '';
+
+ foreach my $macro (qw(PERL_VMS MM_VMS_REVISION MM_VMS_VERSION))
+ {
+ next unless defined $self->{$macro};
+ $make_frag .= "$macro = $self->{$macro}\n";
+ }
+
+ return $make_frag;
+}
+
+
+=item init_VERSION (override)
+
+Override the *DEFINE_VERSION macros with VMS semantics. Translate the
+MAKEMAKER filepath to VMS style.
+
+=cut
+
+sub init_VERSION {
+ my $self = shift;
+
+ $self->SUPER::init_VERSION;
+
+ $self->{DEFINE_VERSION} = '"$(VERSION_MACRO)=""$(VERSION)"""';
+ $self->{XS_DEFINE_VERSION} = '"$(XS_VERSION_MACRO)=""$(XS_VERSION)"""';
+ $self->{MAKEMAKER} = vmsify($INC{'ExtUtils/MakeMaker.pm'});
+}
+
+
+=item constants (override)
+
+Fixes up numerous file and directory macros to insure VMS syntax
+regardless of input syntax. Also makes lists of files
+comma-separated.
+
+=cut
+
+sub constants {
+ my($self) = @_;
+
+ # Be kind about case for pollution
+ for (@ARGV) { $_ = uc($_) if /POLLUTE/i; }
+
+ # Cleanup paths for directories in MMS macros.
+ foreach my $macro ( qw [
+ INST_BIN INST_SCRIPT INST_LIB INST_ARCHLIB
+ PERL_LIB PERL_ARCHLIB PERL_ARCHLIBDEP
+ PERL_INC PERL_SRC ],
+ (map { 'INSTALL'.$_ } $self->installvars),
+ (map { 'DESTINSTALL'.$_ } $self->installvars)
+ )
+ {
+ next unless defined $self->{$macro};
+ next if $macro =~ /MAN/ && $self->{$macro} eq 'none';
+ $self->{$macro} = $self->fixpath($self->{$macro},1);
+ }
+
+ # Cleanup paths for files in MMS macros.
+ foreach my $macro ( qw[LIBPERL_A FIRST_MAKEFILE MAKEFILE_OLD
+ MAKE_APERL_FILE MYEXTLIB] )
+ {
+ next unless defined $self->{$macro};
+ $self->{$macro} = $self->fixpath($self->{$macro},0);
+ }
+
+ # Fixup files for MMS macros
+ # XXX is this list complete?
+ for my $macro (qw/
+ FULLEXT VERSION_FROM
+ / ) {
+ next unless defined $self->{$macro};
+ $self->{$macro} = $self->fixpath($self->{$macro},0);
+ }
+
+
+ for my $macro (qw/
+ OBJECT LDFROM
+ / ) {
+ next unless defined $self->{$macro};
+
+ # Must expand macros before splitting on unescaped whitespace.
+ $self->{$macro} = $self->eliminate_macros($self->{$macro});
+ if ($self->{$macro} =~ /(?{$macro} =~ s/(\\)?\n+\s+/ /g;
+ $self->{$macro} = $self->wraplist(
+ map $self->fixpath($_,0), split /,?(?{$macro}
+ );
+ }
+ else {
+ $self->{$macro} = $self->fixpath($self->{$macro},0);
+ }
+ }
+
+ for my $macro (qw/ XS MAN1PODS MAN3PODS PM /) {
+ # Where is the space coming from? --jhi
+ next unless $self ne " " && defined $self->{$macro};
+ my %tmp = ();
+ for my $key (keys %{$self->{$macro}}) {
+ $tmp{$self->fixpath($key,0)} =
+ $self->fixpath($self->{$macro}{$key},0);
+ }
+ $self->{$macro} = \%tmp;
+ }
+
+ for my $macro (qw/ C O_FILES H /) {
+ next unless defined $self->{$macro};
+ my @tmp = ();
+ for my $val (@{$self->{$macro}}) {
+ push(@tmp,$self->fixpath($val,0));
+ }
+ $self->{$macro} = \@tmp;
+ }
+
+ # mms/k does not define a $(MAKE) macro.
+ $self->{MAKE} = '$(MMS)$(MMSQUALIFIERS)';
+
+ return $self->SUPER::constants;
+}
+
+
+=item special_targets
+
+Clear the default .SUFFIXES and put in our own list.
+
+=cut
+
+sub special_targets {
+ my $self = shift;
+
+ my $make_frag .= <<'MAKE_FRAG';
+.SUFFIXES :
+.SUFFIXES : $(OBJ_EXT) .c .cpp .cxx .xs
+
+MAKE_FRAG
+
+ return $make_frag;
+}
+
+=item cflags (override)
+
+Bypass shell script and produce qualifiers for CC directly (but warn
+user if a shell script for this extension exists). Fold multiple
+/Defines into one, since some C compilers pay attention to only one
+instance of this qualifier on the command line.
+
+=cut
+
+sub cflags {
+ my($self,$libperl) = @_;
+ my($quals) = $self->{CCFLAGS} || $Config{'ccflags'};
+ my($definestr,$undefstr,$flagoptstr) = ('','','');
+ my($incstr) = '/Include=($(PERL_INC)';
+ my($name,$sys,@m);
+
+ ( $name = $self->{NAME} . "_cflags" ) =~ s/:/_/g ;
+ print "Unix shell script ".$Config{"$self->{'BASEEXT'}_cflags"}.
+ " required to modify CC command for $self->{'BASEEXT'}\n"
+ if ($Config{$name});
+
+ if ($quals =~ / -[DIUOg]/) {
+ while ($quals =~ / -([Og])(\d*)\b/) {
+ my($type,$lvl) = ($1,$2);
+ $quals =~ s/ -$type$lvl\b\s*//;
+ if ($type eq 'g') { $flagoptstr = '/NoOptimize'; }
+ else { $flagoptstr = '/Optimize' . (defined($lvl) ? "=$lvl" : ''); }
+ }
+ while ($quals =~ / -([DIU])(\S+)/) {
+ my($type,$def) = ($1,$2);
+ $quals =~ s/ -$type$def\s*//;
+ $def =~ s/"/""/g;
+ if ($type eq 'D') { $definestr .= qq["$def",]; }
+ elsif ($type eq 'I') { $incstr .= ',' . $self->fixpath($def,1); }
+ else { $undefstr .= qq["$def",]; }
+ }
+ }
+ if (length $quals and $quals !~ m!/!) {
+ warn "MM_VMS: Ignoring unrecognized CCFLAGS elements \"$quals\"\n";
+ $quals = '';
+ }
+ $definestr .= q["PERL_POLLUTE",] if $self->{POLLUTE};
+ if (length $definestr) { chop($definestr); $quals .= "/Define=($definestr)"; }
+ if (length $undefstr) { chop($undefstr); $quals .= "/Undef=($undefstr)"; }
+ # Deal with $self->{DEFINE} here since some C compilers pay attention
+ # to only one /Define clause on command line, so we have to
+ # conflate the ones from $Config{'ccflags'} and $self->{DEFINE}
+ # ($self->{DEFINE} has already been VMSified in constants() above)
+ if ($self->{DEFINE}) { $quals .= $self->{DEFINE}; }
+ for my $type (qw(Def Undef)) {
+ my(@terms);
+ while ($quals =~ m:/${type}i?n?e?=([^/]+):ig) {
+ my $term = $1;
+ $term =~ s:^\((.+)\)$:$1:;
+ push @terms, $term;
+ }
+ if ($type eq 'Def') {
+ push @terms, qw[ $(DEFINE_VERSION) $(XS_DEFINE_VERSION) ];
+ }
+ if (@terms) {
+ $quals =~ s:/${type}i?n?e?=[^/]+::ig;
+ # PASTHRU_DEFINE will have its own comma
+ $quals .= "/${type}ine=(" . join(',',@terms) . ($type eq 'Def' ? '$(PASTHRU_DEFINE)' : '') . ')';
+ }
+ }
+
+ $libperl or $libperl = $self->{LIBPERL_A} || "libperl.olb";
+
+ # Likewise with $self->{INC} and /Include
+ if ($self->{'INC'}) {
+ my(@includes) = split(/\s+/,$self->{INC});
+ foreach (@includes) {
+ s/^-I//;
+ $incstr .= ','.$self->fixpath($_,1);
+ }
+ }
+ $quals .= "$incstr)";
+# $quals =~ s/,,/,/g; $quals =~ s/\(,/(/g;
+ $self->{CCFLAGS} = $quals;
+
+ $self->{PERLTYPE} ||= '';
+
+ $self->{OPTIMIZE} ||= $flagoptstr || $Config{'optimize'};
+ if ($self->{OPTIMIZE} !~ m!/!) {
+ if ($self->{OPTIMIZE} =~ m!-g!) { $self->{OPTIMIZE} = '/Debug/NoOptimize' }
+ elsif ($self->{OPTIMIZE} =~ /-O(\d*)/) {
+ $self->{OPTIMIZE} = '/Optimize' . (defined($1) ? "=$1" : '');
+ }
+ else {
+ warn "MM_VMS: Can't parse OPTIMIZE \"$self->{OPTIMIZE}\"; using default\n" if length $self->{OPTIMIZE};
+ $self->{OPTIMIZE} = '/Optimize';
+ }
+ }
+
+ return $self->{CFLAGS} = qq{
+CCFLAGS = $self->{CCFLAGS}
+OPTIMIZE = $self->{OPTIMIZE}
+PERLTYPE = $self->{PERLTYPE}
+};
+}
+
+=item const_cccmd (override)
+
+Adds directives to point C preprocessor to the right place when
+handling #include Esys/foo.hE directives. Also constructs CC
+command line a bit differently than MM_Unix method.
+
+=cut
+
+sub const_cccmd {
+ my($self,$libperl) = @_;
+ my(@m);
+
+ return $self->{CONST_CCCMD} if $self->{CONST_CCCMD};
+ return '' unless $self->needs_linking();
+ if ($Config{'vms_cc_type'} eq 'gcc') {
+ push @m,'
+.FIRST
+ ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" Then Define/NoLog SYS GNU_CC_Include:[VMS]';
+ }
+ elsif ($Config{'vms_cc_type'} eq 'vaxc') {
+ push @m,'
+.FIRST
+ ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").eqs."" Then Define/NoLog SYS Sys$Library
+ ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("VAXC$Include").nes."" Then Define/NoLog SYS VAXC$Include';
+ }
+ else {
+ push @m,'
+.FIRST
+ ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").eqs."" Then Define/NoLog SYS ',
+ ($Config{'archname'} eq 'VMS_AXP' ? 'Sys$Library' : 'DECC$Library_Include'),'
+ ',$self->{NOECHO},'If F$TrnLnm("Sys").eqs."" .and. F$TrnLnm("DECC$System_Include").nes."" Then Define/NoLog SYS DECC$System_Include';
+ }
+
+ push(@m, "\n\nCCCMD = $Config{'cc'} \$(CCFLAGS)\$(OPTIMIZE)\n");
+
+ $self->{CONST_CCCMD} = join('',@m);
+}
+
+
+=item tools_other (override)
+
+Throw in some dubious extra macros for Makefile args.
+
+Also keep around the old $(SAY) macro in case somebody's using it.
+
+=cut
+
+sub tools_other {
+ my($self) = @_;
+
+ # XXX Are these necessary? Does anyone override them? They're longer
+ # than just typing the literal string.
+ my $extra_tools = <<'EXTRA_TOOLS';
+
+# Just in case anyone is using the old macro.
+USEMACROS = $(MACROSTART)
+SAY = $(ECHO)
+
+EXTRA_TOOLS
+
+ return $self->SUPER::tools_other . $extra_tools;
+}
+
+=item init_dist (override)
+
+VMSish defaults for some values.
+
+ macro description default
+
+ ZIPFLAGS flags to pass to ZIP -Vu
+
+ COMPRESS compression command to gzip
+ use for tarfiles
+ SUFFIX suffix to put on -gz
+ compressed files
+
+ SHAR shar command to use vms_share
+
+ DIST_DEFAULT default target to use to tardist
+ create a distribution
+
+ DISTVNAME Use VERSION_SYM instead of $(DISTNAME)-$(VERSION_SYM)
+ VERSION for the name
+
+=cut
+
+sub init_dist {
+ my($self) = @_;
+ $self->{ZIPFLAGS} ||= '-Vu';
+ $self->{COMPRESS} ||= 'gzip';
+ $self->{SUFFIX} ||= '-gz';
+ $self->{SHAR} ||= 'vms_share';
+ $self->{DIST_DEFAULT} ||= 'zipdist';
+
+ $self->SUPER::init_dist;
+
+ $self->{DISTVNAME} = "$self->{DISTNAME}-$self->{VERSION_SYM}"
+ unless $self->{ARGS}{DISTVNAME};
+
+ return;
+}
+
+=item c_o (override)
+
+Use VMS syntax on command line. In particular, $(DEFINE) and
+$(PERL_INC) have been pulled into $(CCCMD). Also use MM[SK] macros.
+
+=cut
+
+sub c_o {
+ my($self) = @_;
+ return '' unless $self->needs_linking();
+ '
+.c$(OBJ_EXT) :
+ $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+
+.cpp$(OBJ_EXT) :
+ $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cpp /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+
+.cxx$(OBJ_EXT) :
+ $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).cxx /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+
+';
+}
+
+=item xs_c (override)
+
+Use MM[SK] macros.
+
+=cut
+
+sub xs_c {
+ my($self) = @_;
+ return '' unless $self->needs_linking();
+ '
+.xs.c :
+ $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
+ $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
+';
+}
+
+=item xs_o (override)
+
+Use MM[SK] macros, and VMS command line for C compiler.
+
+=cut
+
+sub xs_o {
+ my ($self) = @_;
+ return '' unless $self->needs_linking();
+ my $frag = '
+.xs$(OBJ_EXT) :
+ $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs >$(MMS$TARGET_NAME).xsc
+ $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
+ $(CCCMD) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+';
+ if ($self->{XSMULTI}) {
+ for my $ext ($self->_xs_list_basenames) {
+ my $version = $self->parse_version("$ext.pm");
+ my $ccflags = $self->{CCFLAGS};
+ $ccflags =~ s/\$\(DEFINE_VERSION\)/\"VERSION_MACRO=\\"\"$version\\"\"/;
+ $ccflags =~ s/\$\(XS_DEFINE_VERSION\)/\"XS_VERSION_MACRO=\\"\"$version\\"\"/;
+ $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'INC');
+ $self->_xsbuild_replace_macro($ccflags, 'xs', $ext, 'DEFINE');
+
+ $frag .= _sprintf562 <<'EOF', $ext, $ccflags;
+
+%1$s$(OBJ_EXT) : %1$s.xs
+ $(XSUBPPRUN) $(XSPROTOARG) $(XSUBPPARGS) $(MMS$TARGET_NAME).xs > $(MMS$TARGET_NAME).xsc
+ $(MV) $(MMS$TARGET_NAME).xsc $(MMS$TARGET_NAME).c
+ $(CC)%2$s$(OPTIMIZE) $(CCCDLFLAGS) $(MMS$TARGET_NAME).c /OBJECT=$(MMS$TARGET_NAME)$(OBJ_EXT)
+EOF
+ }
+ }
+ $frag;
+}
+
+=item _xsbuild_replace_macro (override)
+
+There is no simple replacement possible since a qualifier and all its
+subqualifiers must be considered together, so we use our own utility
+routine for the replacement.
+
+=cut
+
+sub _xsbuild_replace_macro {
+ my ($self, undef, $xstype, $ext, $varname) = @_;
+ my $value = $self->_xsbuild_value($xstype, $ext, $varname);
+ return unless defined $value;
+ $_[1] = _vms_replace_qualifier($self, $_[1], $value, $varname);
+}
+
+=item _xsbuild_value (override)
+
+Convert the extension spec to Unix format, as that's what will
+match what's in the XSBUILD data structure.
+
+=cut
+
+sub _xsbuild_value {
+ my ($self, $xstype, $ext, $varname) = @_;
+ $ext = unixify($ext);
+ return $self->SUPER::_xsbuild_value($xstype, $ext, $varname);
+}
+
+sub _vms_replace_qualifier {
+ my ($self, $flags, $newflag, $macro) = @_;
+ my $qual_type;
+ my $type_suffix;
+ my $quote_subquals = 0;
+ my @subquals_new = split /\s+/, $newflag;
+
+ if ($macro eq 'DEFINE') {
+ $qual_type = 'Def';
+ $type_suffix = 'ine';
+ map { $_ =~ s/^-D// } @subquals_new;
+ $quote_subquals = 1;
+ }
+ elsif ($macro eq 'INC') {
+ $qual_type = 'Inc';
+ $type_suffix = 'lude';
+ map { $_ =~ s/^-I//; $_ = $self->fixpath($_) } @subquals_new;
+ }
+
+ my @subquals = ();
+ while ($flags =~ m:/${qual_type}\S{0,4}=([^/]+):ig) {
+ my $term = $1;
+ $term =~ s/\"//g;
+ $term =~ s:^\((.+)\)$:$1:;
+ push @subquals, split /,/, $term;
+ }
+ for my $new (@subquals_new) {
+ my ($sq_new, $sqval_new) = split /=/, $new;
+ my $replaced_old = 0;
+ for my $old (@subquals) {
+ my ($sq, $sqval) = split /=/, $old;
+ if ($sq_new eq $sq) {
+ $old = $sq_new;
+ $old .= '=' . $sqval_new if defined($sqval_new) and length($sqval_new);
+ $replaced_old = 1;
+ last;
+ }
+ }
+ push @subquals, $new unless $replaced_old;
+ }
+
+ if (@subquals) {
+ $flags =~ s:/${qual_type}\S{0,4}=[^/]+::ig;
+ # add quotes if requested but not for unexpanded macros
+ map { $_ = qq/"$_"/ if $_ !~ m/^\$\(/ } @subquals if $quote_subquals;
+ $flags .= "/${qual_type}$type_suffix=(" . join(',',@subquals) . ')';
+ }
+
+ return $flags;
+}
+
+
+sub xs_dlsyms_ext {
+ '.opt';
+}
+
+=item dlsyms (override)
+
+Create VMS linker options files specifying universal symbols for this
+extension's shareable image(s), and listing other shareable images or
+libraries to which it should be linked.
+
+=cut
+
+sub dlsyms {
+ my ($self, %attribs) = @_;
+ return '' unless $self->needs_linking;
+ $self->xs_dlsyms_iterator;
+}
+
+sub xs_make_dlsyms {
+ my ($self, $attribs, $target, $dep, $name, $dlbase, $funcs, $funclist, $imports, $vars, $extra) = @_;
+ my @m;
+ my $instloc;
+ if ($self->{XSMULTI}) {
+ my ($v, $d, $f) = File::Spec->splitpath($target);
+ my @d = File::Spec->splitdir($d);
+ shift @d if $d[0] eq 'lib';
+ $instloc = $self->catfile('$(INST_ARCHLIB)', 'auto', @d, $f);
+ push @m,"\ndynamic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
+ unless $self->{SKIPHASH}{'dynamic'};
+ push @m,"\nstatic :: $instloc\n\t\$(NOECHO) \$(NOOP)\n"
+ unless $self->{SKIPHASH}{'static'};
+ push @m, "\n", sprintf <<'EOF', $instloc, $target;
+%s : %s
+ $(CP) $(MMS$SOURCE) $(MMS$TARGET)
+EOF
+ }
+ else {
+ push @m,"\ndynamic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
+ unless $self->{SKIPHASH}{'dynamic'};
+ push @m,"\nstatic :: \$(INST_ARCHAUTODIR)$self->{BASEEXT}.opt\n\t\$(NOECHO) \$(NOOP)\n"
+ unless $self->{SKIPHASH}{'static'};
+ push @m, "\n", sprintf <<'EOF', $target;
+$(INST_ARCHAUTODIR)$(BASEEXT).opt : %s
+ $(CP) $(MMS$SOURCE) $(MMS$TARGET)
+EOF
+ }
+ push @m,
+ "\n$target : $dep\n\t",
+ q!$(PERLRUN) -MExtUtils::Mksymlists -e "Mksymlists('NAME'=>'!, $name,
+ q!', 'DLBASE' => '!,$dlbase,
+ q!', 'DL_FUNCS' => !,neatvalue($funcs),
+ q!, 'FUNCLIST' => !,neatvalue($funclist),
+ q!, 'IMPORTS' => !,neatvalue($imports),
+ q!, 'DL_VARS' => !, neatvalue($vars);
+ push @m, $extra if defined $extra;
+ push @m, qq!);"\n\t!;
+ # Can't use dlbase as it's been through mod2fname.
+ my $olb_base = basename($target, '.opt');
+ if ($self->{XSMULTI}) {
+ # We've been passed everything but the kitchen sink -- and the location of the
+ # static library we're using to build the dynamic library -- so concoct that
+ # location from what we do have.
+ my $olb_dir = $self->catdir(dirname($instloc), $olb_base);
+ push @m, qq!\$(PERL) -e "print ""${olb_dir}${olb_base}\$(LIB_EXT)/Include=!;
+ push @m, ($Config{d_vms_case_sensitive_symbols} ? uc($olb_base) : $olb_base);
+ push @m, '\n' . $olb_dir . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
+ }
+ else {
+ push @m, qq!\$(PERL) -e "print ""\$(INST_ARCHAUTODIR)${olb_base}\$(LIB_EXT)/Include=!;
+ if ($self->{OBJECT} =~ /\bBASEEXT\b/ or
+ $self->{OBJECT} =~ /\b$self->{BASEEXT}\b/i) {
+ push @m, ($Config{d_vms_case_sensitive_symbols}
+ ? uc($self->{BASEEXT}) :'$(BASEEXT)');
+ }
+ else { # We don't have a "main" object file, so pull 'em all in
+ # Upcase module names if linker is being case-sensitive
+ my($upcase) = $Config{d_vms_case_sensitive_symbols};
+ my(@omods) = split ' ', $self->eliminate_macros($self->{OBJECT});
+ for (@omods) {
+ s/\.[^.]*$//; # Trim off file type
+ s[\$\(\w+_EXT\)][]; # even as a macro
+ s/.*[:>\/\]]//; # Trim off dir spec
+ $_ = uc if $upcase;
+ };
+ my(@lines);
+ my $tmp = shift @omods;
+ foreach my $elt (@omods) {
+ $tmp .= ",$elt";
+ if (length($tmp) > 80) { push @lines, $tmp; $tmp = ''; }
+ }
+ push @lines, $tmp;
+ push @m, '(', join( qq[, -\\n\\t"";" >>\$(MMS\$TARGET)\n\t\$(PERL) -e "print ""], @lines),')';
+ }
+ push @m, '\n$(INST_ARCHAUTODIR)' . $olb_base . '$(LIB_EXT)/Library\n"";" >>$(MMS$TARGET)',"\n";
+ }
+ if (length $self->{LDLOADLIBS}) {
+ my($line) = '';
+ foreach my $lib (split ' ', $self->{LDLOADLIBS}) {
+ $lib =~ s%\$%\\\$%g; # Escape '$' in VMS filespecs
+ if (length($line) + length($lib) > 160) {
+ push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n";
+ $line = $lib . '\n';
+ }
+ else { $line .= $lib . '\n'; }
+ }
+ push @m, "\t\$(PERL) -e \"print qq{$line}\" >>\$(MMS\$TARGET)\n" if $line;
+ }
+ join '', @m;
+}
+
+
+=item xs_obj_opt
+
+Override to fixup -o flags.
+
+=cut
+
+sub xs_obj_opt {
+ my ($self, $output_file) = @_;
+ "/OBJECT=$output_file";
+}
+
+=item dynamic_lib (override)
+
+Use VMS Link command.
+
+=cut
+
+sub xs_dynamic_lib_macros {
+ my ($self, $attribs) = @_;
+ my $otherldflags = $attribs->{OTHERLDFLAGS} || "";
+ my $inst_dynamic_dep = $attribs->{INST_DYNAMIC_DEP} || "";
+ sprintf <<'EOF', $otherldflags, $inst_dynamic_dep;
+# This section creates the dynamically loadable objects from relevant
+# objects and possibly $(MYEXTLIB).
+OTHERLDFLAGS = %s
+INST_DYNAMIC_DEP = %s
+EOF
+}
+
+sub xs_make_dynamic_lib {
+ my ($self, $attribs, $from, $to, $todir, $ldfrom, $exportlist) = @_;
+ my $shr = $Config{'dbgprefix'} . 'PerlShr';
+ $exportlist =~ s/.def$/.opt/; # it's a linker options file
+ # 1 2 3 4 5
+ _sprintf562 <<'EOF', $to, $todir, $exportlist, $shr, "$shr Sys\$Share:$shr.$Config{'dlext'}";
+%1$s : $(INST_STATIC) $(PERL_INC)perlshr_attr.opt %2$s$(DFSEP).exists %3$s $(PERL_ARCHIVE) $(INST_DYNAMIC_DEP)
+ If F$TrnLNm("%4$s").eqs."" Then Define/NoLog/User %5$s
+ Link $(LDFLAGS) /Shareable=$(MMS$TARGET)$(OTHERLDFLAGS) %3$s/Option,$(PERL_INC)perlshr_attr.opt/Option
+EOF
+}
+
+=item xs_make_static_lib (override)
+
+Use VMS commands to manipulate object library.
+
+=cut
+
+sub xs_make_static_lib {
+ my ($self, $object, $to, $todir) = @_;
+
+ my @objects;
+ if ($self->{XSMULTI}) {
+ # The extension name should be the main object file name minus file type.
+ my $lib = $object;
+ $lib =~ s/\$\(OBJ_EXT\)\z//;
+ my $override = $self->_xsbuild_value('xs', $lib, 'OBJECT');
+ $object = $override if defined $override;
+ @objects = map { $self->fixpath($_,0) } split /(?{MYEXTLIB};
+
+ push(@m,"\t",'If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)',"\n");
+
+ # if there was a library to copy, then we can't use MMS$SOURCE_LIST,
+ # 'cause it's a library and you can't stick them in other libraries.
+ # In that case, we use $OBJECT instead and hope for the best
+ if ($self->{MYEXTLIB}) {
+ for my $obj (@objects) {
+ push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) ' . $obj,"\n");
+ }
+ }
+ else {
+ push(@m,"\t",'Library/Object/Replace $(MMS$TARGET) $(MMS$SOURCE_LIST)',"\n");
+ }
+
+ push @m, "\t\$(NOECHO) \$(PERL) -e 1 >\$(INST_ARCHAUTODIR)extralibs.ld\n";
+ foreach my $lib (split ' ', $self->{EXTRALIBS}) {
+ push(@m,"\t",'$(NOECHO) $(PERL) -e "print qq{',$lib,'\n}" >>$(INST_ARCHAUTODIR)extralibs.ld',"\n");
+ }
+ join('',@m);
+}
+
+
+=item static_lib_pure_cmd (override)
+
+Use VMS commands to manipulate object library.
+
+=cut
+
+sub static_lib_pure_cmd {
+ my ($self, $from) = @_;
+
+ sprintf <<'MAKE_FRAG', $from;
+ If F$Search("$(MMS$TARGET)").eqs."" Then Library/Object/Create $(MMS$TARGET)
+ Library/Object/Replace $(MMS$TARGET) %s
+MAKE_FRAG
+}
+
+=item xs_static_lib_is_xs
+
+=cut
+
+sub xs_static_lib_is_xs {
+ return 1;
+}
+
+=item extra_clean_files
+
+Clean up some OS specific files. Plus the temp file used to shorten
+a lot of commands. And the name mangler database.
+
+=cut
+
+sub extra_clean_files {
+ return qw(
+ *.Map *.Dmp *.Lis *.cpp *.$(DLEXT) *.Opt $(BASEEXT).bso
+ .MM_Tmp cxx_repository
+ );
+}
+
+
+=item zipfile_target
+
+=item tarfile_target
+
+=item shdist_target
+
+Syntax for invoking shar, tar and zip differs from that for Unix.
+
+=cut
+
+sub zipfile_target {
+ my($self) = shift;
+
+ return <<'MAKE_FRAG';
+$(DISTVNAME).zip : distdir
+ $(PREOP)
+ $(ZIP) "$(ZIPFLAGS)" $(MMS$TARGET) [.$(DISTVNAME)...]*.*;
+ $(RM_RF) $(DISTVNAME)
+ $(POSTOP)
+MAKE_FRAG
+}
+
+sub tarfile_target {
+ my($self) = shift;
+
+ return <<'MAKE_FRAG';
+$(DISTVNAME).tar$(SUFFIX) : distdir
+ $(PREOP)
+ $(TO_UNIX)
+ $(TAR) "$(TARFLAGS)" $(DISTVNAME).tar [.$(DISTVNAME)...]
+ $(RM_RF) $(DISTVNAME)
+ $(COMPRESS) $(DISTVNAME).tar
+ $(POSTOP)
+MAKE_FRAG
+}
+
+sub shdist_target {
+ my($self) = shift;
+
+ return <<'MAKE_FRAG';
+shdist : distdir
+ $(PREOP)
+ $(SHAR) [.$(DISTVNAME)...]*.*; $(DISTVNAME).share
+ $(RM_RF) $(DISTVNAME)
+ $(POSTOP)
+MAKE_FRAG
+}
+
+
+# --- Test and Installation Sections ---
+
+=item install (override)
+
+Work around DCL's 255 character limit several times,and use
+VMS-style command line quoting in a few cases.
+
+=cut
+
+sub install {
+ my($self, %attribs) = @_;
+ my(@m);
+
+ push @m, q[
+install :: all pure_install doc_install
+ $(NOECHO) $(NOOP)
+
+install_perl :: all pure_perl_install doc_perl_install
+ $(NOECHO) $(NOOP)
+
+install_site :: all pure_site_install doc_site_install
+ $(NOECHO) $(NOOP)
+
+install_vendor :: all pure_vendor_install doc_vendor_install
+ $(NOECHO) $(NOOP)
+
+pure_install :: pure_$(INSTALLDIRS)_install
+ $(NOECHO) $(NOOP)
+
+doc_install :: doc_$(INSTALLDIRS)_install
+ $(NOECHO) $(NOOP)
+
+pure__install : pure_site_install
+ $(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site"
+
+doc__install : doc_site_install
+ $(NOECHO) $(ECHO) "INSTALLDIRS not defined, defaulting to INSTALLDIRS=site"
+
+# This hack brought to you by DCL's 255-character command line limit
+pure_perl_install ::
+];
+ push @m,
+q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(PERL_ARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
+ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLARCHLIB)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
+] unless $self->{NO_PACKLIST};
+
+ push @m,
+q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLPRIVLIB)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLARCHLIB)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLBIN)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR) $(DESTINSTALLMAN1DIR) " >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLMAN3DIR)" >>.MM_tmp
+ $(NOECHO) $(MOD_INSTALL) <.MM_tmp
+ $(NOECHO) $(RM_F) .MM_tmp
+ $(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q["
+
+# Likewise
+pure_site_install ::
+];
+ push @m,
+q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(SITEARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
+ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLSITEARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
+] unless $self->{NO_PACKLIST};
+
+ push @m,
+q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLSITELIB)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLSITEARCH)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLSITEBIN)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLSITEMAN1DIR)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLSITEMAN3DIR)" >>.MM_tmp
+ $(NOECHO) $(MOD_INSTALL) <.MM_tmp
+ $(NOECHO) $(RM_F) .MM_tmp
+ $(NOECHO) $(WARN_IF_OLD_PACKLIST) "].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q["
+
+pure_vendor_install ::
+];
+ push @m,
+q[ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'read|'.File::Spec->catfile('$(VENDORARCHEXP)','auto','$(FULLEXT)','.packlist').'|'" >.MM_tmp
+ $(NOECHO) $(PERLRUN) "-MFile::Spec" -e "print 'write|'.File::Spec->catfile('$(DESTINSTALLVENDORARCH)','auto','$(FULLEXT)','.packlist').'|'" >>.MM_tmp
+] unless $self->{NO_PACKLIST};
+
+ push @m,
+q[ $(NOECHO) $(ECHO_N) "$(INST_LIB)|$(DESTINSTALLVENDORLIB)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_ARCHLIB)|$(DESTINSTALLVENDORARCH)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_BIN)|$(DESTINSTALLVENDORBIN)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_SCRIPT)|$(DESTINSTALLSCRIPT)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN1DIR)|$(DESTINSTALLVENDORMAN1DIR)|" >>.MM_tmp
+ $(NOECHO) $(ECHO_N) "$(INST_MAN3DIR)|$(DESTINSTALLVENDORMAN3DIR)" >>.MM_tmp
+ $(NOECHO) $(MOD_INSTALL) <.MM_tmp
+ $(NOECHO) $(RM_F) .MM_tmp
+
+];
+
+ push @m, q[
+# Ditto
+doc_perl_install ::
+ $(NOECHO) $(NOOP)
+
+# And again
+doc_site_install ::
+ $(NOECHO) $(NOOP)
+
+doc_vendor_install ::
+ $(NOECHO) $(NOOP)
+
+] if $self->{NO_PERLLOCAL};
+
+ push @m, q[
+# Ditto
+doc_perl_install ::
+ $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
+ $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+ $(NOECHO) $(ECHO_N) "installed into|$(INSTALLPRIVLIB)|" >.MM_tmp
+ $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
+ $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
+ $(NOECHO) $(RM_F) .MM_tmp
+
+# And again
+doc_site_install ::
+ $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
+ $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+ $(NOECHO) $(ECHO_N) "installed into|$(INSTALLSITELIB)|" >.MM_tmp
+ $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
+ $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
+ $(NOECHO) $(RM_F) .MM_tmp
+
+doc_vendor_install ::
+ $(NOECHO) $(ECHO) "Appending installation info to ].$self->catfile($self->{DESTINSTALLARCHLIB}, 'perllocal.pod').q["
+ $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+ $(NOECHO) $(ECHO_N) "installed into|$(INSTALLVENDORLIB)|" >.MM_tmp
+ $(NOECHO) $(ECHO_N) "LINKTYPE|$(LINKTYPE)|VERSION|$(VERSION)|EXE_FILES|$(EXE_FILES) " >>.MM_tmp
+ $(NOECHO) $(DOC_INSTALL) "Module" "$(NAME)" <.MM_tmp >>].$self->catfile($self->{DESTINSTALLARCHLIB},'perllocal.pod').q[
+ $(NOECHO) $(RM_F) .MM_tmp
+
+] unless $self->{NO_PERLLOCAL};
+
+ push @m, q[
+uninstall :: uninstall_from_$(INSTALLDIRS)dirs
+ $(NOECHO) $(NOOP)
+
+uninstall_from_perldirs ::
+ $(NOECHO) $(UNINSTALL) ].$self->catfile($self->{PERL_ARCHLIB},'auto',$self->{FULLEXT},'.packlist').q[
+
+uninstall_from_sitedirs ::
+ $(NOECHO) $(UNINSTALL) ].$self->catfile($self->{SITEARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[
+
+uninstall_from_vendordirs ::
+ $(NOECHO) $(UNINSTALL) ].$self->catfile($self->{VENDORARCHEXP},'auto',$self->{FULLEXT},'.packlist').q[
+];
+
+ join('',@m);
+}
+
+=item perldepend (override)
+
+Use VMS-style syntax for files; it's cheaper to just do it directly here
+than to have the L method call C
+repeatedly. Also, if we have to rebuild Config.pm, use MM[SK] to do it.
+
+=cut
+
+sub perldepend {
+ my($self) = @_;
+ my(@m);
+
+ if ($self->{OBJECT}) {
+ # Need to add an object file dependency on the perl headers.
+ # this is very important for XS modules in perl.git development.
+
+ push @m, $self->_perl_header_files_fragment(""); # empty separator on VMS as its in the $(PERL_INC)
+ }
+
+ if ($self->{PERL_SRC}) {
+ my(@macros);
+ my($mmsquals) = '$(USEMAKEFILE)[.vms]$(FIRST_MAKEFILE)';
+ push(@macros,'__AXP__=1') if $Config{'archname'} eq 'VMS_AXP';
+ push(@macros,'DECC=1') if $Config{'vms_cc_type'} eq 'decc';
+ push(@macros,'GNUC=1') if $Config{'vms_cc_type'} eq 'gcc';
+ push(@macros,'SOCKET=1') if $Config{'d_has_sockets'};
+ push(@macros,qq["CC=$Config{'cc'}"]) if $Config{'cc'} =~ m!/!;
+ $mmsquals .= '$(USEMACROS)' . join(',',@macros) . '$(MACROEND)' if @macros;
+ push(@m,q[
+# Check for unpropagated config.sh changes. Should never happen.
+# We do NOT just update config.h because that is not sufficient.
+# An out of date config.h is not fatal but complains loudly!
+$(PERL_INC)config.h : $(PERL_SRC)config.sh
+ $(NOOP)
+
+$(PERL_ARCHLIB)Config.pm : $(PERL_SRC)config.sh
+ $(NOECHO) Write Sys$Error "$(PERL_ARCHLIB)Config.pm may be out of date with config.h or genconfig.pl"
+ olddef = F$Environment("Default")
+ Set Default $(PERL_SRC)
+ $(MMS)],$mmsquals,);
+ if ($self->{PERL_ARCHLIB} =~ m|\[-| && $self->{PERL_SRC} =~ m|(\[-+)|) {
+ my($prefix,$target) = ($1,$self->fixpath('$(PERL_ARCHLIB)Config.pm',0));
+ $target =~ s/\Q$prefix/[/;
+ push(@m," $target");
+ }
+ else { push(@m,' $(MMS$TARGET)'); }
+ push(@m,q[
+ Set Default 'olddef'
+]);
+ }
+
+ push(@m, join(" ", map($self->fixpath($_,0),sort values %{$self->{XS}}))." : \$(XSUBPPDEPS)\n")
+ if %{$self->{XS}};
+
+ join('',@m);
+}
+
+
+=item makeaperl (override)
+
+Undertake to build a new set of Perl images using VMS commands. Since
+VMS does dynamic loading, it's not necessary to statically link each
+extension into the Perl image, so this isn't the normal build path.
+Consequently, it hasn't really been tested, and may well be incomplete.
+
+=cut
+
+our %olbs; # needs to be localized
+
+sub makeaperl {
+ my($self, %attribs) = @_;
+ my($makefilename, $searchdirs, $static, $extra, $perlinc, $target, $tmpdir, $libperl) =
+ @attribs{qw(MAKE DIRS STAT EXTRA INCL TARGET TMP LIBPERL)};
+ my(@m);
+ push @m, "
+# --- MakeMaker makeaperl section ---
+MAP_TARGET = $target
+";
+ return join '', @m if $self->{PARENT};
+
+ my($dir) = join ":", @{$self->{DIR}};
+
+ unless ($self->{MAKEAPERL}) {
+ push @m, q{
+$(MAKE_APERL_FILE) : $(FIRST_MAKEFILE)
+ $(NOECHO) $(ECHO) "Writing ""$(MMS$TARGET)"" for this $(MAP_TARGET)"
+ $(NOECHO) $(PERLRUNINST) \
+ Makefile.PL DIR=}, $dir, q{ \
+ FIRST_MAKEFILE=$(MAKE_APERL_FILE) LINKTYPE=static \
+ MAKEAPERL=1 NORECURS=1 };
+
+ push @m, map(q[ \\\n\t\t"$_"], @ARGV),q{
+
+$(MAP_TARGET) :: $(MAKE_APERL_FILE)
+ $(MAKE)$(USEMAKEFILE)$(MAKE_APERL_FILE) static $(MMS$TARGET)
+};
+ push @m, "\n";
+
+ return join '', @m;
+ }
+
+
+ my($linkcmd,@optlibs,@staticpkgs,$extralist,$targdir,$libperldir,%libseen);
+ local($_);
+
+ # The front matter of the linkcommand...
+ $linkcmd = join ' ', $Config{'ld'},
+ grep($_, @Config{qw(large split ldflags ccdlflags)});
+ $linkcmd =~ s/\s+/ /g;
+
+ # Which *.olb files could we make use of...
+ local(%olbs); # XXX can this be lexical?
+ $olbs{$self->{INST_ARCHAUTODIR}} = "$self->{BASEEXT}\$(LIB_EXT)";
+ require File::Find;
+ File::Find::find(sub {
+ return unless m/\Q$self->{LIB_EXT}\E$/;
+ return if m/^libperl/;
+
+ if( exists $self->{INCLUDE_EXT} ){
+ my $found = 0;
+
+ (my $xx = $File::Find::name) =~ s,.*?/auto/,,;
+ $xx =~ s,/?$_,,;
+ $xx =~ s,/,::,g;
+
+ # Throw away anything not explicitly marked for inclusion.
+ # DynaLoader is implied.
+ foreach my $incl ((@{$self->{INCLUDE_EXT}},'DynaLoader')){
+ if( $xx eq $incl ){
+ $found++;
+ last;
+ }
+ }
+ return unless $found;
+ }
+ elsif( exists $self->{EXCLUDE_EXT} ){
+ (my $xx = $File::Find::name) =~ s,.*?/auto/,,;
+ $xx =~ s,/?$_,,;
+ $xx =~ s,/,::,g;
+
+ # Throw away anything explicitly marked for exclusion
+ foreach my $excl (@{$self->{EXCLUDE_EXT}}){
+ return if( $xx eq $excl );
+ }
+ }
+
+ $olbs{$ENV{DEFAULT}} = $_;
+ }, grep( -d $_, @{$searchdirs || []}));
+
+ # We trust that what has been handed in as argument will be buildable
+ $static = [] unless $static;
+ @olbs{@{$static}} = (1) x @{$static};
+
+ $extra = [] unless $extra && ref $extra eq 'ARRAY';
+ # Sort the object libraries in inverse order of
+ # filespec length to try to insure that dependent extensions
+ # will appear before their parents, so the linker will
+ # search the parent library to resolve references.
+ # (e.g. Intuit::DWIM will precede Intuit, so unresolved
+ # references from [.intuit.dwim]dwim.obj can be found
+ # in [.intuit]intuit.olb).
+ for (sort { length($a) <=> length($b) || $a cmp $b } keys %olbs) {
+ next unless $olbs{$_} =~ /\Q$self->{LIB_EXT}\E$/;
+ my($dir) = $self->fixpath($_,1);
+ my($extralibs) = $dir . "extralibs.ld";
+ my($extopt) = $dir . $olbs{$_};
+ $extopt =~ s/$self->{LIB_EXT}$/.opt/;
+ push @optlibs, "$dir$olbs{$_}";
+ # Get external libraries this extension will need
+ if (-f $extralibs ) {
+ my %seenthis;
+ open my $list, "<", $extralibs or warn $!,next;
+ while (<$list>) {
+ chomp;
+ # Include a library in the link only once, unless it's mentioned
+ # multiple times within a single extension's options file, in which
+ # case we assume the builder needed to search it again later in the
+ # link.
+ my $skip = exists($libseen{$_}) && !exists($seenthis{$_});
+ $libseen{$_}++; $seenthis{$_}++;
+ next if $skip;
+ push @$extra,$_;
+ }
+ }
+ # Get full name of extension for ExtUtils::Miniperl
+ if (-f $extopt) {
+ open my $opt, '<', $extopt or die $!;
+ while (<$opt>) {
+ next unless /(?:UNIVERSAL|VECTOR)=boot_([\w_]+)/;
+ my $pkg = $1;
+ $pkg =~ s#__*#::#g;
+ push @staticpkgs,$pkg;
+ }
+ }
+ }
+ # Place all of the external libraries after all of the Perl extension
+ # libraries in the final link, in order to maximize the opportunity
+ # for XS code from multiple extensions to resolve symbols against the
+ # same external library while only including that library once.
+ push @optlibs, @$extra;
+
+ $target = "Perl$Config{'exe_ext'}" unless $target;
+ my $shrtarget;
+ ($shrtarget,$targdir) = fileparse($target);
+ $shrtarget =~ s/^([^.]*)/$1Shr/;
+ $shrtarget = $targdir . $shrtarget;
+ $target = "Perlshr.$Config{'dlext'}" unless $target;
+ $tmpdir = "[]" unless $tmpdir;
+ $tmpdir = $self->fixpath($tmpdir,1);
+ if (@optlibs) { $extralist = join(' ',@optlibs); }
+ else { $extralist = ''; }
+ # Let ExtUtils::Liblist find the necessary libs for us (but skip PerlShr)
+ # that's what we're building here).
+ push @optlibs, grep { !/PerlShr/i } split ' ', +($self->ext())[2];
+ if ($libperl) {
+ unless (-f $libperl || -f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',$libperl))) {
+ print "Warning: $libperl not found\n";
+ undef $libperl;
+ }
+ }
+ unless ($libperl) {
+ if (defined $self->{PERL_SRC}) {
+ $libperl = $self->catfile($self->{PERL_SRC},"libperl$self->{LIB_EXT}");
+ } elsif (-f ($libperl = $self->catfile($Config{'installarchlib'},'CORE',"libperl$self->{LIB_EXT}")) ) {
+ } else {
+ print "Warning: $libperl not found
+ If you're going to build a static perl binary, make sure perl is installed
+ otherwise ignore this warning\n";
+ }
+ }
+ $libperldir = $self->fixpath((fileparse($libperl))[1],1);
+
+ push @m, '
+# Fill in the target you want to produce if it\'s not perl
+MAP_TARGET = ',$self->fixpath($target,0),'
+MAP_SHRTARGET = ',$self->fixpath($shrtarget,0),"
+MAP_LINKCMD = $linkcmd
+MAP_PERLINC = ", $perlinc ? map('"$_" ',@{$perlinc}) : '',"
+MAP_EXTRA = $extralist
+MAP_LIBPERL = ",$self->fixpath($libperl,0),'
+';
+
+
+ push @m,"\n${tmpdir}Makeaperl.Opt : \$(MAP_EXTRA)\n";
+ foreach (@optlibs) {
+ push @m,' $(NOECHO) $(PERL) -e "print q{',$_,'}" >>$(MMS$TARGET)',"\n";
+ }
+ push @m,"\n${tmpdir}PerlShr.Opt :\n\t";
+ push @m,'$(NOECHO) $(PERL) -e "print q{$(MAP_SHRTARGET)}" >$(MMS$TARGET)',"\n";
+
+ push @m,'
+$(MAP_SHRTARGET) : $(MAP_LIBPERL) Makeaperl.Opt ',"${libperldir}Perlshr_Attr.Opt",'
+ $(MAP_LINKCMD)/Shareable=$(MMS$TARGET) $(MAP_LIBPERL), Makeaperl.Opt/Option ',"${libperldir}Perlshr_Attr.Opt/Option",'
+$(MAP_TARGET) : $(MAP_SHRTARGET) ',"${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}PerlShr.Opt",'
+ $(MAP_LINKCMD) ',"${tmpdir}perlmain\$(OBJ_EXT)",', PerlShr.Opt/Option
+ $(NOECHO) $(ECHO) "To install the new ""$(MAP_TARGET)"" binary, say"
+ $(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) inst_perl $(USEMACROS)MAP_TARGET=$(MAP_TARGET)$(ENDMACRO)"
+ $(NOECHO) $(ECHO) "To remove the intermediate files, say
+ $(NOECHO) $(ECHO) " $(MAKE)$(USEMAKEFILE)$(FIRST_MAKEFILE) map_clean"
+';
+ push @m,"\n${tmpdir}perlmain.c : \$(FIRST_MAKEFILE)\n\t\$(NOECHO) \$(PERL) -e 1 >${tmpdir}Writemain.tmp\n";
+ push @m, "# More from the 255-char line length limit\n";
+ foreach (@staticpkgs) {
+ push @m,' $(NOECHO) $(PERL) -e "print q{',$_,qq[}" >>${tmpdir}Writemain.tmp\n];
+ }
+
+ push @m, sprintf <<'MAKE_FRAG', $tmpdir, $tmpdir;
+ $(NOECHO) $(PERL) $(MAP_PERLINC) -ane "use ExtUtils::Miniperl; writemain(@F)" %sWritemain.tmp >$(MMS$TARGET)
+ $(NOECHO) $(RM_F) %sWritemain.tmp
+MAKE_FRAG
+
+ push @m, q[
+# Still more from the 255-char line length limit
+doc_inst_perl :
+ $(NOECHO) $(MKPATH) $(DESTINSTALLARCHLIB)
+ $(NOECHO) $(ECHO) "Perl binary $(MAP_TARGET)|" >.MM_tmp
+ $(NOECHO) $(ECHO) "MAP_STATIC|$(MAP_STATIC)|" >>.MM_tmp
+ $(NOECHO) $(PERL) -pl040 -e " " ].$self->catfile('$(INST_ARCHAUTODIR)','extralibs.all'),q[ >>.MM_tmp
+ $(NOECHO) $(ECHO) -e "MAP_LIBPERL|$(MAP_LIBPERL)|" >>.MM_tmp
+ $(NOECHO) $(DOC_INSTALL) <.MM_tmp >>].$self->catfile('$(DESTINSTALLARCHLIB)','perllocal.pod').q[
+ $(NOECHO) $(RM_F) .MM_tmp
+];
+
+ push @m, "
+inst_perl : pure_inst_perl doc_inst_perl
+ \$(NOECHO) \$(NOOP)
+
+pure_inst_perl : \$(MAP_TARGET)
+ $self->{CP} \$(MAP_SHRTARGET) ",$self->fixpath($Config{'installbin'},1),"
+ $self->{CP} \$(MAP_TARGET) ",$self->fixpath($Config{'installbin'},1),"
+
+clean :: map_clean
+ \$(NOECHO) \$(NOOP)
+
+map_clean :
+ \$(RM_F) ${tmpdir}perlmain\$(OBJ_EXT) ${tmpdir}perlmain.c \$(FIRST_MAKEFILE)
+ \$(RM_F) ${tmpdir}Makeaperl.Opt ${tmpdir}PerlShr.Opt \$(MAP_TARGET)
+";
+
+ join '', @m;
+}
+
+
+# --- Output postprocessing section ---
+
+=item maketext_filter (override)
+
+Ensure that colons marking targets are preceded by space, in order
+to distinguish the target delimiter from a colon appearing as
+part of a filespec.
+
+=cut
+
+sub maketext_filter {
+ my($self, $text) = @_;
+
+ $text =~ s/^([^\s:=]+)(:+\s)/$1 $2/mg;
+ return $text;
+}
+
+=item prefixify (override)
+
+prefixifying on VMS is simple. Each should simply be:
+
+ perl_root:[some.dir]
+
+which can just be converted to:
+
+ volume:[your.prefix.some.dir]
+
+otherwise you get the default layout.
+
+In effect, your search prefix is ignored and $Config{vms_prefix} is
+used instead.
+
+=cut
+
+sub prefixify {
+ my($self, $var, $sprefix, $rprefix, $default) = @_;
+
+ # Translate $(PERLPREFIX) to a real path.
+ $rprefix = $self->eliminate_macros($rprefix);
+ $rprefix = vmspath($rprefix) if $rprefix;
+ $sprefix = vmspath($sprefix) if $sprefix;
+
+ $default = vmsify($default)
+ unless $default =~ /\[.*\]/;
+
+ (my $var_no_install = $var) =~ s/^install//;
+ my $path = $self->{uc $var} ||
+ $ExtUtils::MM_Unix::Config_Override{lc $var} ||
+ $Config{lc $var} || $Config{lc $var_no_install};
+
+ if( !$path ) {
+ warn " no Config found for $var.\n" if $Verbose >= 2;
+ $path = $self->_prefixify_default($rprefix, $default);
+ }
+ elsif( !$self->{ARGS}{PREFIX} || !$self->file_name_is_absolute($path) ) {
+ # do nothing if there's no prefix or if its relative
+ }
+ elsif( $sprefix eq $rprefix ) {
+ warn " no new prefix.\n" if $Verbose >= 2;
+ }
+ else {
+
+ warn " prefixify $var => $path\n" if $Verbose >= 2;
+ warn " from $sprefix to $rprefix\n" if $Verbose >= 2;
+
+ my($path_vol, $path_dirs) = $self->splitpath( $path );
+ if( $path_vol eq $Config{vms_prefix}.':' ) {
+ warn " $Config{vms_prefix}: seen\n" if $Verbose >= 2;
+
+ $path_dirs =~ s{^\[}{\[.} unless $path_dirs =~ m{^\[\.};
+ $path = $self->_catprefix($rprefix, $path_dirs);
+ }
+ else {
+ $path = $self->_prefixify_default($rprefix, $default);
+ }
+ }
+
+ print " now $path\n" if $Verbose >= 2;
+ return $self->{uc $var} = $path;
+}
+
+
+sub _prefixify_default {
+ my($self, $rprefix, $default) = @_;
+
+ warn " cannot prefix, using default.\n" if $Verbose >= 2;
+
+ if( !$default ) {
+ warn "No default!\n" if $Verbose >= 1;
+ return;
+ }
+ if( !$rprefix ) {
+ warn "No replacement prefix!\n" if $Verbose >= 1;
+ return '';
+ }
+
+ return $self->_catprefix($rprefix, $default);
+}
+
+sub _catprefix {
+ my($self, $rprefix, $default) = @_;
+
+ my($rvol, $rdirs) = $self->splitpath($rprefix);
+ if( $rvol ) {
+ return $self->catpath($rvol,
+ $self->catdir($rdirs, $default),
+ ''
+ )
+ }
+ else {
+ return $self->catdir($rdirs, $default);
+ }
+}
+
+
+=item cd
+
+=cut
+
+sub cd {
+ my($self, $dir, @cmds) = @_;
+
+ $dir = vmspath($dir);
+
+ my $cmd = join "\n\t", map "$_", @cmds;
+
+ # No leading tab makes it look right when embedded
+ my $make_frag = sprintf <<'MAKE_FRAG', $dir, $cmd;
+startdir = F$Environment("Default")
+ Set Default %s
+ %s
+ Set Default 'startdir'
+MAKE_FRAG
+
+ # No trailing newline makes this easier to embed
+ chomp $make_frag;
+
+ return $make_frag;
+}
+
+
+=item oneliner
+
+=cut
+
+sub oneliner {
+ my($self, $cmd, $switches) = @_;
+ $switches = [] unless defined $switches;
+
+ # Strip leading and trailing newlines
+ $cmd =~ s{^\n+}{};
+ $cmd =~ s{\n+$}{};
+
+ my @cmds = split /\n/, $cmd;
+ $cmd = join " \n\t -e ", map $self->quote_literal($_), @cmds;
+ $cmd = $self->escape_newlines($cmd);
+
+ # Switches must be quoted else they will be lowercased.
+ $switches = join ' ', map { qq{"$_"} } @$switches;
+
+ return qq{\$(ABSPERLRUN) $switches -e $cmd "--"};
+}
+
+
+=item B
+
+perl trips up on "" thinking it's an input redirect. So we use the
+native Write command instead. Besides, it's faster.
+
+=cut
+
+sub echo {
+ my($self, $text, $file, $opts) = @_;
+
+ # Compatibility with old options
+ if( !ref $opts ) {
+ my $append = $opts;
+ $opts = { append => $append || 0 };
+ }
+ my $opencmd = $opts->{append} ? 'Open/Append' : 'Open/Write';
+
+ $opts->{allow_variables} = 0 unless defined $opts->{allow_variables};
+
+ my $ql_opts = { allow_variables => $opts->{allow_variables} };
+
+ my @cmds = ("\$(NOECHO) $opencmd MMECHOFILE $file ");
+ push @cmds, map { '$(NOECHO) Write MMECHOFILE '.$self->quote_literal($_, $ql_opts) }
+ split /\n/, $text;
+ push @cmds, '$(NOECHO) Close MMECHOFILE';
+ return @cmds;
+}
+
+
+=item quote_literal
+
+=cut
+
+sub quote_literal {
+ my($self, $text, $opts) = @_;
+ $opts->{allow_variables} = 1 unless defined $opts->{allow_variables};
+
+ # I believe this is all we should need.
+ $text =~ s{"}{""}g;
+
+ $text = $opts->{allow_variables}
+ ? $self->escape_dollarsigns($text) : $self->escape_all_dollarsigns($text);
+
+ return qq{"$text"};
+}
+
+=item escape_dollarsigns
+
+Quote, don't escape.
+
+=cut
+
+sub escape_dollarsigns {
+ my($self, $text) = @_;
+
+ # Quote dollar signs which are not starting a variable
+ $text =~ s{\$ (?!\() }{"\$"}gx;
+
+ return $text;
+}
+
+
+=item escape_all_dollarsigns
+
+Quote, don't escape.
+
+=cut
+
+sub escape_all_dollarsigns {
+ my($self, $text) = @_;
+
+ # Quote dollar signs
+ $text =~ s{\$}{"\$\"}gx;
+
+ return $text;
+}
+
+=item escape_newlines
+
+=cut
+
+sub escape_newlines {
+ my($self, $text) = @_;
+
+ $text =~ s{\n}{-\n}g;
+
+ return $text;
+}
+
+=item max_exec_len
+
+256 characters.
+
+=cut
+
+sub max_exec_len {
+ my $self = shift;
+
+ return $self->{_MAX_EXEC_LEN} ||= 256;
+}
+
+=item init_linker
+
+=cut
+
+sub init_linker {
+ my $self = shift;
+ $self->{EXPORT_LIST} ||= '$(BASEEXT).opt';
+
+ my $shr = $Config{dbgprefix} . 'PERLSHR';
+ if ($self->{PERL_SRC}) {
+ $self->{PERL_ARCHIVE} ||=
+ $self->catfile($self->{PERL_SRC}, "$shr.$Config{'dlext'}");
+ }
+ else {
+ $self->{PERL_ARCHIVE} ||=
+ $ENV{$shr} ? $ENV{$shr} : "Sys\$Share:$shr.$Config{'dlext'}";
+ }
+
+ $self->{PERL_ARCHIVEDEP} ||= '';
+ $self->{PERL_ARCHIVE_AFTER} ||= '';
+}
+
+
+=item catdir (override)
+
+=item catfile (override)
+
+Eliminate the macros in the output to the MMS/MMK file.
+
+(L used to do this for us, but it's being removed)
+
+=cut
+
+sub catdir {
+ my $self = shift;
+
+ # Process the macros on VMS MMS/MMK
+ my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_;
+
+ my $dir = $self->SUPER::catdir(@args);
+
+ # Fix up the directory and force it to VMS format.
+ $dir = $self->fixpath($dir, 1);
+
+ return $dir;
+}
+
+sub catfile {
+ my $self = shift;
+
+ # Process the macros on VMS MMS/MMK
+ my @args = map { m{\$\(} ? $self->eliminate_macros($_) : $_ } @_;
+
+ my $file = $self->SUPER::catfile(@args);
+
+ $file = vmsify($file);
+
+ return $file
+}
+
+
+=item eliminate_macros
+
+Expands MM[KS]/Make macros in a text string, using the contents of
+identically named elements of C<%$self>, and returns the result
+as a file specification in Unix syntax.
+
+NOTE: This is the canonical version of the method. The version in
+L is deprecated.
+
+=cut
+
+sub eliminate_macros {
+ my($self,$path) = @_;
+ return '' unless $path;
+ $self = {} unless ref $self;
+
+ my($npath) = unixify($path);
+ # sometimes unixify will return a string with an off-by-one trailing null
+ $npath =~ s{\0$}{};
+
+ my($complex) = 0;
+ my($head,$macro,$tail);
+
+ # perform m##g in scalar context so it acts as an iterator
+ while ($npath =~ m#(.*?)\$\((\S+?)\)(.*)#gs) {
+ if (defined $self->{$2}) {
+ ($head,$macro,$tail) = ($1,$2,$3);
+ if (ref $self->{$macro}) {
+ if (ref $self->{$macro} eq 'ARRAY') {
+ $macro = join ' ', @{$self->{$macro}};
+ }
+ else {
+ print "Note: can't expand macro \$($macro) containing ",ref($self->{$macro}),
+ "\n\t(using MMK-specific deferred substitutuon; MMS will break)\n";
+ $macro = "\cB$macro\cB";
+ $complex = 1;
+ }
+ }
+ else {
+ $macro = $self->{$macro};
+ # Don't unixify if there is unescaped whitespace
+ $macro = unixify($macro) unless ($macro =~ /(?fixpath($path);
+ my $path = $mm->fixpath($path, $is_dir);
+
+Catchall routine to clean up problem MM[SK]/Make macros. Expands macros
+in any directory specification, in order to avoid juxtaposing two
+VMS-syntax directories when MM[SK] is run. Also expands expressions which
+are all macro, so that we can tell how long the expansion is, and avoid
+overrunning DCL's command buffer when MM[KS] is running.
+
+fixpath() checks to see whether the result matches the name of a
+directory in the current default directory and returns a directory or
+file specification accordingly. C<$is_dir> can be set to true to
+force fixpath() to consider the path to be a directory or false to force
+it to be a file.
+
+NOTE: This is the canonical version of the method. The version in
+L is deprecated.
+
+=cut
+
+sub fixpath {
+ my($self,$path,$force_path) = @_;
+ return '' unless $path;
+ $self = bless {}, $self unless ref $self;
+ my($fixedpath,$prefix,$name);
+
+ if ($path =~ m#^\$\([^\)]+\)\Z(?!\n)#s || $path =~ m#[/:>\]]#) {
+ if ($force_path or $path =~ /(?:DIR\)|\])\Z(?!\n)/) {
+ $fixedpath = vmspath($self->eliminate_macros($path));
+ }
+ else {
+ $fixedpath = vmsify($self->eliminate_macros($path));
+ }
+ }
+ elsif ((($prefix,$name) = ($path =~ m#^\$\(([^\)]+)\)(.+)#s)) && $self->{$prefix}) {
+ my($vmspre) = $self->eliminate_macros("\$($prefix)");
+ # is it a dir or just a name?
+ $vmspre = ($vmspre =~ m|/| or $prefix =~ /DIR\Z(?!\n)/) ? vmspath($vmspre) : '';
+ $fixedpath = ($vmspre ? $vmspre : $self->{$prefix}) . $name;
+ $fixedpath = vmspath($fixedpath) if $force_path;
+ }
+ else {
+ $fixedpath = $path;
+ $fixedpath = vmspath($fixedpath) if $force_path;
+ }
+ # No hints, so we try to guess
+ if (!defined($force_path) and $fixedpath !~ /[:>(.\]]/) {
+ $fixedpath = vmspath($fixedpath) if -d $fixedpath;
+ }
+
+ # Trim off root dirname if it's had other dirs inserted in front of it.
+ $fixedpath =~ s/\.000000([\]>])/$1/;
+ # Special case for VMS absolute directory specs: these will have had device
+ # prepended during trip through Unix syntax in eliminate_macros(), since
+ # Unix syntax has no way to express "absolute from the top of this device's
+ # directory tree".
+ if ($path =~ /^[\[>][^.\-]/) { $fixedpath =~ s/^[^\[<]+//; }
+
+ return $fixedpath;
+}
+
+
+=item os_flavor
+
+VMS is VMS.
+
+=cut
+
+sub os_flavor {
+ return('VMS');
+}
+
+
+=item is_make_type (override)
+
+None of the make types being checked for is viable on VMS,
+plus our $self->{MAKE} is an unexpanded (and unexpandable)
+macro whose value is known only to the make utility itself.
+
+=cut
+
+sub is_make_type {
+ my($self, $type) = @_;
+ return 0;
+}
+
+
+=item make_type (override)
+
+Returns a suitable string describing the type of makefile being written.
+
+=cut
+
+sub make_type { "$Config{make}-style"; }
+
+
+=back
+
+
+=head1 AUTHOR
+
+Original author Charles Bailey F
+
+Maintained by Michael G Schwern F
+
+See L for patching and contact information.
+
+
+=cut
+
+1;
+
diff --git a/src/main/perl/lib/ExtUtils/MM_VOS.pm b/src/main/perl/lib/ExtUtils/MM_VOS.pm
new file mode 100644
index 000000000..3ae39d8d3
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_VOS.pm
@@ -0,0 +1,52 @@
+package ExtUtils::MM_VOS;
+
+use strict;
+use warnings;
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Unix;
+our @ISA = qw(ExtUtils::MM_Unix);
+
+
+=head1 NAME
+
+ExtUtils::MM_VOS - VOS specific subclass of ExtUtils::MM_Unix
+
+=head1 SYNOPSIS
+
+ Don't use this module directly.
+ Use ExtUtils::MM and let it choose.
+
+=head1 DESCRIPTION
+
+This is a subclass of L which contains functionality for
+VOS.
+
+Unless otherwise stated it works just like ExtUtils::MM_Unix.
+
+=head2 Overridden methods
+
+=head3 extra_clean_files
+
+Cleanup VOS core files
+
+=cut
+
+sub extra_clean_files {
+ return qw(*.kp);
+}
+
+
+=head1 AUTHOR
+
+Michael G Schwern with code from ExtUtils::MM_Unix
+
+=head1 SEE ALSO
+
+L
+
+=cut
+
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MM_Win32.pm b/src/main/perl/lib/ExtUtils/MM_Win32.pm
index 91c559b45..2e10002ba 100644
--- a/src/main/perl/lib/ExtUtils/MM_Win32.pm
+++ b/src/main/perl/lib/ExtUtils/MM_Win32.pm
@@ -2,7 +2,7 @@ package ExtUtils::MM_Win32;
use strict;
use warnings;
-our $VERSION = '7.70_perlonjava';
+our $VERSION = '7.78_perlonjava';
# MM_Win32 provides Windows-specific methods for ExtUtils::MakeMaker.
# In PerlOnJava, we only implement the methods needed by CPAN.pm.
diff --git a/src/main/perl/lib/ExtUtils/MM_Win95.pm b/src/main/perl/lib/ExtUtils/MM_Win95.pm
new file mode 100644
index 000000000..8a90a0d58
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MM_Win95.pm
@@ -0,0 +1,77 @@
+package ExtUtils::MM_Win95;
+
+use strict;
+use warnings;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+require ExtUtils::MM_Win32;
+our @ISA = qw(ExtUtils::MM_Win32);
+
+use ExtUtils::MakeMaker::Config;
+
+
+=head1 NAME
+
+ExtUtils::MM_Win95 - method to customize MakeMaker for Win9X
+
+=head1 SYNOPSIS
+
+ You should not be using this module directly.
+
+=head1 DESCRIPTION
+
+This is a subclass of L containing changes necessary
+to get MakeMaker playing nice with command.com and other Win9Xisms.
+
+=head2 Overridden methods
+
+Most of these make up for limitations in the Win9x/nmake command shell.
+
+=over 4
+
+
+=item max_exec_len
+
+Win98 chokes on things like Encode if we set the max length to nmake's max
+of 2K. So we go for a more conservative value of 1K.
+
+=cut
+
+sub max_exec_len {
+ my $self = shift;
+
+ return $self->{_MAX_EXEC_LEN} ||= 1024;
+}
+
+
+=item os_flavor
+
+Win95 and Win98 and WinME are collectively Win9x and Win32
+
+=cut
+
+sub os_flavor {
+ my $self = shift;
+ return ($self->SUPER::os_flavor, 'Win9x');
+}
+
+
+=back
+
+
+=head1 AUTHOR
+
+Code originally inside MM_Win32. Original author unknown.
+
+Currently maintained by Michael G Schwern C.
+
+Send patches and ideas to C.
+
+See https://metacpan.org/release/ExtUtils-MakeMaker.
+
+=cut
+
+
+1;
diff --git a/src/main/perl/lib/ExtUtils/MY.pm b/src/main/perl/lib/ExtUtils/MY.pm
index 8678730d6..d1735969c 100644
--- a/src/main/perl/lib/ExtUtils/MY.pm
+++ b/src/main/perl/lib/ExtUtils/MY.pm
@@ -2,7 +2,7 @@ package ExtUtils::MY;
use strict;
use warnings;
-our $VERSION = '7.70_perlonjava';
+our $VERSION = '7.78_perlonjava';
# MY is used for user customizations in Makefile.PL
# In PerlOnJava, this is a stub since we don't generate Makefiles.
diff --git a/src/main/perl/lib/ExtUtils/MakeMaker.pm b/src/main/perl/lib/ExtUtils/MakeMaker.pm
index b206e5d75..8c47c0dfb 100644
--- a/src/main/perl/lib/ExtUtils/MakeMaker.pm
+++ b/src/main/perl/lib/ExtUtils/MakeMaker.pm
@@ -2,7 +2,7 @@ package ExtUtils::MakeMaker;
use strict;
use warnings;
-our $VERSION = '7.70';
+our $VERSION = '7.78';
use Exporter 'import';
our @EXPORT = qw(WriteMakefile prompt);
@@ -378,10 +378,11 @@ sub _create_stub_makefile {
my $perl = $^X;
# Build test command - run all t/*.t files using Perl for cross-platform compatibility
+ # Set PERL5LIB to include blib/lib and blib/arch so test subprocesses can find the module
my $test_cmd;
if (-d 't') {
# Use Perl one-liner with Test::Harness for cross-platform test running
- $test_cmd = qq{$perl -MTest::Harness -e "runtests(glob(q{t/*.t}))"};
+ $test_cmd = qq{PERL5LIB="./blib/lib:./blib/arch:\$\$PERL5LIB" $perl -MTest::Harness -e "runtests(glob(q{t/*.t}))"};
} else {
$test_cmd = qq{$perl -e "print qq{PerlOnJava: No tests found (no t/ directory)\\n}"};
}
diff --git a/src/main/perl/lib/ExtUtils/MakeMaker/Config.pm b/src/main/perl/lib/ExtUtils/MakeMaker/Config.pm
index ea370c326..ebde3c486 100644
--- a/src/main/perl/lib/ExtUtils/MakeMaker/Config.pm
+++ b/src/main/perl/lib/ExtUtils/MakeMaker/Config.pm
@@ -1,39 +1,41 @@
package ExtUtils::MakeMaker::Config;
+
use strict;
use warnings;
-our $VERSION = '7.70_perlonjava';
-
-# This module provides a Config hash that MakeMaker uses.
-# It's a wrapper around the Config module.
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
-use Config;
+use Config ();
-# Re-export %Config
+# Give us an overridable config.
our %Config = %Config::Config;
-# Add some PerlOnJava-specific values
-$Config{perlonjava} = 1;
-$Config{usedl} = 0; # No dynamic loading of C code
-
sub import {
- my $class = shift;
my $caller = caller;
-
- no strict 'refs';
- *{"${caller}::Config"} = \%Config;
+
+ no strict 'refs'; ## no critic
+ *{$caller.'::Config'} = \%Config;
}
1;
-__END__
=head1 NAME
-ExtUtils::MakeMaker::Config - Config wrapper for PerlOnJava
+ExtUtils::MakeMaker::Config - Wrapper around Config.pm
+
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MakeMaker::Config;
+ print $Config{installbin}; # or whatever
+
=head1 DESCRIPTION
-Provides access to %Config for MakeMaker scripts.
+B
+
+A very thin wrapper around Config.pm so MakeMaker is easier to test.
=cut
diff --git a/src/main/perl/lib/ExtUtils/MakeMaker/FAQ.pod b/src/main/perl/lib/ExtUtils/MakeMaker/FAQ.pod
new file mode 100644
index 000000000..e17f10a71
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MakeMaker/FAQ.pod
@@ -0,0 +1,667 @@
+package ExtUtils::MakeMaker::FAQ;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+1;
+__END__
+
+=head1 NAME
+
+ExtUtils::MakeMaker::FAQ - Frequently Asked Questions About MakeMaker
+
+=head1 DESCRIPTION
+
+FAQs, tricks and tips for L.
+
+
+=head2 Module Installation
+
+=over 4
+
+=item How do I install a module into my home directory?
+
+If you're not the Perl administrator you probably don't have
+permission to install a module to its default location. Ways of handling
+this with a B less manual effort on your part are L
+and L.
+
+Otherwise, you can install it for your own use into your home directory
+like so:
+
+ # Non-unix folks, replace ~ with /path/to/your/home/dir
+ perl Makefile.PL INSTALL_BASE=~
+
+This will put modules into F<~/lib/perl5>, man pages into F<~/man> and
+programs into F<~/bin>.
+
+To ensure your Perl programs can see these newly installed modules,
+set your C environment variable to F<~/lib/perl5> or tell
+each of your programs to look in that directory with the following:
+
+ use lib "$ENV{HOME}/lib/perl5";
+
+or if $ENV{HOME} isn't set and you don't want to set it for some
+reason, do it the long way.
+
+ use lib "/path/to/your/home/dir/lib/perl5";
+
+=item How do I get MakeMaker and Module::Build to install to the same place?
+
+Module::Build, as of 0.28, supports two ways to install to the same
+location as MakeMaker.
+
+We highly recommend the install_base method, its the simplest and most
+closely approximates the expected behavior of an installation prefix.
+
+1) Use INSTALL_BASE / C<--install_base>
+
+MakeMaker (as of 6.31) and Module::Build (as of 0.28) both can install
+to the same locations using the "install_base" concept. See
+L for details. To get MM and MB to
+install to the same location simply set INSTALL_BASE in MM and
+C<--install_base> in MB to the same location.
+
+ perl Makefile.PL INSTALL_BASE=/whatever
+ perl Build.PL --install_base /whatever
+
+This works most like other language's behavior when you specify a
+prefix. We recommend this method.
+
+2) Use PREFIX / C<--prefix>
+
+Module::Build 0.28 added support for C<--prefix> which works like
+MakeMaker's PREFIX.
+
+ perl Makefile.PL PREFIX=/whatever
+ perl Build.PL --prefix /whatever
+
+We highly discourage this method. It should only be used if you know
+what you're doing and specifically need the PREFIX behavior. The
+PREFIX algorithm is complicated and focused on matching the system
+installation.
+
+=item How do I keep from installing man pages?
+
+Recent versions of MakeMaker will only install man pages on Unix-like
+operating systems by default. To generate manpages on non-Unix operating
+systems, make the "manifypods" target.
+
+For an individual module:
+
+ perl Makefile.PL INSTALLMAN1DIR=none INSTALLMAN3DIR=none
+
+If you want to suppress man page installation for all modules you have
+to reconfigure Perl and tell it 'none' when it asks where to install
+man pages.
+
+
+=item How do I use a module without installing it?
+
+Two ways. One is to build the module normally...
+
+ perl Makefile.PL
+ make
+ make test
+
+...and then use L to point Perl at the built but uninstalled module:
+
+ perl -Mblib script.pl
+ perl -Mblib -e '...'
+
+The other is to install the module in a temporary location.
+
+ perl Makefile.PL INSTALL_BASE=~/tmp
+ make
+ make test
+ make install
+
+And then set PERL5LIB to F<~/tmp/lib/perl5>. This works well when you
+have multiple modules to work with. It also ensures that the module
+goes through its full installation process which may modify it.
+Again, L may assist you here.
+
+=item How can I organize tests into subdirectories and have them run?
+
+Let's take the following test directory structure:
+
+ t/foo/sometest.t
+ t/bar/othertest.t
+ t/bar/baz/anothertest.t
+
+Now, inside of the C function in your F, specify
+where your tests are located with the C directive:
+
+ test => {TESTS => 't/*.t t/*/*.t t/*/*/*.t'}
+
+The first entry in the string will run all tests in the top-level F
+directory. The second will run all test files located in any subdirectory under
+F . The third, runs all test files within any subdirectory within any other
+subdirectory located under F .
+
+Note that you do not have to use wildcards. You can specify explicitly which
+subdirectories to run tests in:
+
+ test => {TESTS => 't/*.t t/foo/*.t t/bar/baz/*.t'}
+
+=item PREFIX vs INSTALL_BASE from Module::Build::Cookbook
+
+The behavior of PREFIX is complicated and depends closely on how your
+Perl is configured. The resulting installation locations will vary
+from machine to machine and even different installations of Perl on the
+same machine. Because of this, its difficult to document where prefix
+will place your modules.
+
+In contrast, INSTALL_BASE has predictable, easy to explain installation
+locations. Now that Module::Build and MakeMaker both have INSTALL_BASE
+there is little reason to use PREFIX other than to preserve your existing
+installation locations. If you are starting a fresh Perl installation we
+encourage you to use INSTALL_BASE. If you have an existing installation
+installed via PREFIX, consider moving it to an installation structure
+matching INSTALL_BASE and using that instead.
+
+=item Generating *.pm files with substitutions eg of $VERSION
+
+If you want to configure your module files for local conditions, or to
+automatically insert a version number, you can use EUMM's C
+capability, where it will automatically run each F<*.PL> it finds to
+generate its basename. For instance:
+
+ # Makefile.PL:
+ require 'common.pl';
+ my $version = get_version();
+ my @pms = qw(Foo.pm);
+ WriteMakefile(
+ NAME => 'Foo',
+ VERSION => $version,
+ PM => { map { ($_ => "\$(INST_LIB)/$_") } @pms },
+ clean => { FILES => join ' ', @pms },
+ );
+
+ # common.pl:
+ sub get_version { '0.04' }
+ sub process { my $v = get_version(); s/__VERSION__/$v/g; }
+ 1;
+
+ # Foo.pm.PL:
+ require 'common.pl';
+ $_ = join '', ;
+ process();
+ my $file = shift;
+ open my $fh, '>', $file or die "$file: $!";
+ print $fh $_;
+ __DATA__
+ package Foo;
+ our $VERSION = '__VERSION__';
+ 1;
+
+You may notice that C is not specified above, since the default
+of mapping each .PL file to its basename works well.
+
+If the generated module were architecture-specific, you could replace
+C<$(INST_LIB)> above with C<$(INST_ARCHLIB)>, although if you locate
+modules under F, that would involve ensuring any C in front
+of the module location were removed.
+
+=back
+
+=head2 Common errors and problems
+
+=over 4
+
+=item "No rule to make target `/usr/lib/perl5/CORE/config.h', needed by `Makefile'"
+
+Just what it says, you're missing that file. MakeMaker uses it to
+determine if perl has been rebuilt since the Makefile was made. It's
+a bit of a bug that it halts installation.
+
+Some operating systems don't ship the CORE directory with their base
+perl install. To solve the problem, you likely need to install a perl
+development package such as perl-devel (CentOS, Fedora and other
+Redhat systems) or perl (Ubuntu and other Debian systems).
+
+=back
+
+=head2 Philosophy and History
+
+=over 4
+
+=item Why not just use ?
+
+Why did MakeMaker reinvent the build configuration wheel? Why not
+just use autoconf or automake or ppm or Ant or ...
+
+There are many reasons, but the major one is cross-platform
+compatibility.
+
+Perl is one of the most ported pieces of software ever. It works on
+operating systems I've never even heard of (see perlport for details).
+It needs a build tool that can work on all those platforms and with
+any wacky C compilers and linkers they might have.
+
+No such build tool exists. Even make itself has wildly different
+dialects. So we have to build our own.
+
+
+=item What is Module::Build and how does it relate to MakeMaker?
+
+Module::Build is a project by Ken Williams to supplant MakeMaker.
+Its primary advantages are:
+
+=over 8
+
+=item * pure perl. no make, no shell commands
+
+=item * easier to customize
+
+=item * cleaner internals
+
+=item * less cruft
+
+=back
+
+Module::Build was long the official heir apparent to MakeMaker. The
+rate of both its development and adoption has slowed in recent years,
+though, and it is unclear what the future holds for it. That said,
+Module::Build set the stage for I to become the heir to
+MakeMaker. MakeMaker's maintainers have long said that it is a dead
+end and should be kept functioning, while being cautious about extending
+with new features.
+
+=back
+
+=head2 Module Writing
+
+=over 4
+
+=item How do I keep my $VERSION up to date without resetting it manually?
+
+Often you want to manually set the $VERSION in the main module
+distribution because this is the version that everybody sees on CPAN
+and maybe you want to customize it a bit. But for all the other
+modules in your dist, $VERSION is really just bookkeeping and all that's
+important is it goes up every time the module is changed. Doing this
+by hand is a pain and you often forget.
+
+Probably the easiest way to do this is using F in
+L:
+
+ perl-reversion -bump
+
+If your version control system supports revision numbers (git doesn't
+easily), the simplest way to do it automatically is to use its revision
+number (you are using version control, right?).
+
+In CVS, RCS and SVN you use $Revision$ (see the documentation of your
+version control system for details). Every time the file is checked
+in the $Revision$ will be updated, updating your $VERSION.
+
+SVN uses a simple integer for $Revision$ so you can adapt it for your
+$VERSION like so:
+
+ ($VERSION) = q$Revision$ =~ /(\d+)/;
+
+In CVS and RCS version 1.9 is followed by 1.10. Since CPAN compares
+version numbers numerically we use a sprintf() to convert 1.9 to 1.009
+and 1.10 to 1.010 which compare properly.
+
+ $VERSION = sprintf "%d.%03d", q$Revision$ =~ /(\d+)\.(\d+)/g;
+
+If branches are involved (ie. $Revision: 1.5.3.4$) it's a little more
+complicated.
+
+ # must be all on one line or MakeMaker will get confused.
+ $VERSION = do { my @r = (q$Revision$ =~ /\d+/g); sprintf "%d."."%03d" x $#r, @r };
+
+In SVN, $Revision$ should be the same for every file in the project so
+they would all have the same $VERSION. CVS and RCS have a different
+$Revision$ per file so each file will have a different $VERSION.
+Distributed version control systems, such as SVK, may have a different
+$Revision$ based on who checks out the file, leading to a different $VERSION
+on each machine! Finally, some distributed version control systems, such
+as darcs, have no concept of revision number at all.
+
+
+=item What's this F thing and how did it get in my F?!
+
+F is a module meta-data file pioneered by Module::Build and
+automatically generated as part of the 'distdir' target (and thus
+'dist'). See L.
+
+To shut off its generation, pass the C flag to C.
+
+
+=item How do I delete everything not in my F?
+
+Some folks are surprised that C does not delete
+everything not listed in their MANIFEST (thus making a clean
+distribution) but only tells them what they need to delete. This is
+done because it is considered too dangerous. While developing your
+module you might write a new file, not add it to the MANIFEST, then
+run a C and be sad because your new work was deleted.
+
+If you really want to do this, you can use
+C to read the MANIFEST and File::Find
+to delete the files. But you have to be careful. Here's a script to
+do that. Use at your own risk. Have fun blowing holes in your foot.
+
+ #!/usr/bin/perl -w
+
+ use strict;
+
+ use File::Spec;
+ use File::Find;
+ use ExtUtils::Manifest qw(maniread);
+
+ my %manifest = map {( $_ => 1 )}
+ grep { File::Spec->canonpath($_) }
+ keys %{ maniread() };
+
+ if( !keys %manifest ) {
+ print "No files found in MANIFEST. Stopping.\n";
+ exit;
+ }
+
+ find({
+ wanted => sub {
+ my $path = File::Spec->canonpath($_);
+
+ return unless -f $path;
+ return if exists $manifest{ $path };
+
+ print "unlink $path\n";
+ unlink $path;
+ },
+ no_chdir => 1
+ },
+ "."
+ );
+
+
+=item Which tar should I use on Windows?
+
+We recommend ptar from Archive::Tar not older than 1.66 with '-C' option.
+
+=item Which zip should I use on Windows for '[ndg]make zipdist'?
+
+We recommend InfoZIP: L
+
+
+=back
+
+=head2 XS
+
+=over 4
+
+=item How do I prevent "object version X.XX does not match bootstrap parameter Y.YY" errors?
+
+XS code is very sensitive to the module version number and will
+complain if the version number in your Perl module doesn't match. If
+you change your module's version # without rerunning Makefile.PL the old
+version number will remain in the Makefile, causing the XS code to be built
+with the wrong number.
+
+To avoid this, you can force the Makefile to be rebuilt whenever you
+change the module containing the version number by adding this to your
+WriteMakefile() arguments.
+
+ depend => { '$(FIRST_MAKEFILE)' => '$(VERSION_FROM)' }
+
+
+=item How do I make two or more XS files coexist in the same directory?
+
+Sometimes you need to have two and more XS files in the same package.
+There are three ways: C, separate directories, and bootstrapping
+one XS from another.
+
+=over 8
+
+=item XSMULTI
+
+Structure your modules so they are all located under F, such that
+C is in F and F, etc. Have your
+top-level C set the variable C to a true value.
+
+Er, that's it.
+
+=item Separate directories
+
+Put each XS files into separate directories, each with their own
+F. Make sure each of those Fs has the correct
+C, C, C etc. You will need to make sure the top-level
+F refers to each of these using C.
+
+=item Bootstrapping
+
+Let's assume that we have a package C, which includes
+C and C modules each having a separate XS
+file. First we use the following I:
+
+ use ExtUtils::MakeMaker;
+
+ WriteMakefile(
+ NAME => 'Cool::Foo',
+ VERSION_FROM => 'Foo.pm',
+ OBJECT => q/$(O_FILES)/,
+ # ... other attrs ...
+ );
+
+Notice the C attribute. MakeMaker generates the following
+variables in I:
+
+ # Handy lists of source code files:
+ XS_FILES= Bar.xs \
+ Foo.xs
+ C_FILES = Bar.c \
+ Foo.c
+ O_FILES = Bar.o \
+ Foo.o
+
+Therefore we can use the C variable to tell MakeMaker to use
+these objects into the shared library.
+
+That's pretty much it. Now write I and I, I
+and I, where I bootstraps the shared library and
+I simply loading I.
+
+The only issue left is to how to bootstrap I. This is done
+from I:
+
+ MODULE = Cool::Foo PACKAGE = Cool::Foo
+
+ BOOT:
+ # boot the second XS file
+ boot_Cool__Bar(aTHX_ cv);
+
+If you have more than two files, this is the place where you should
+boot extra XS files from.
+
+The following four files sum up all the details discussed so far.
+
+ Foo.pm:
+ -------
+ package Cool::Foo;
+
+ require DynaLoader;
+
+ our @ISA = qw(DynaLoader);
+ our $VERSION = '0.01';
+ bootstrap Cool::Foo $VERSION;
+
+ 1;
+
+ Bar.pm:
+ -------
+ package Cool::Bar;
+
+ use Cool::Foo; # bootstraps Bar.xs
+
+ 1;
+
+ Foo.xs:
+ -------
+ #include "EXTERN.h"
+ #include "perl.h"
+ #include "XSUB.h"
+
+ MODULE = Cool::Foo PACKAGE = Cool::Foo
+
+ BOOT:
+ # boot the second XS file
+ boot_Cool__Bar(aTHX_ cv);
+
+ MODULE = Cool::Foo PACKAGE = Cool::Foo PREFIX = cool_foo_
+
+ void
+ cool_foo_perl_rules()
+
+ CODE:
+ fprintf(stderr, "Cool::Foo says: Perl Rules\n");
+
+ Bar.xs:
+ -------
+ #include "EXTERN.h"
+ #include "perl.h"
+ #include "XSUB.h"
+
+ MODULE = Cool::Bar PACKAGE = Cool::Bar PREFIX = cool_bar_
+
+ void
+ cool_bar_perl_rules()
+
+ CODE:
+ fprintf(stderr, "Cool::Bar says: Perl Rules\n");
+
+And of course a very basic test:
+
+ t/cool.t:
+ --------
+ use Test::More tests => 1;
+ use Cool::Foo;
+ use Cool::Bar;
+ Cool::Foo::perl_rules();
+ Cool::Bar::perl_rules();
+ ok 1;
+
+This tip has been brought to you by Nick Ing-Simmons and Stas Bekman.
+
+An alternative way to achieve this can be seen in L
+and L.
+
+=back
+
+=back
+
+=head1 DESIGN
+
+=head2 MakeMaker object hierarchy (simplified)
+
+What most people need to know (superclasses on top.)
+
+ ExtUtils::MM_Any
+ |
+ ExtUtils::MM_Unix
+ |
+ ExtUtils::MM_{Current OS}
+ |
+ ExtUtils::MakeMaker
+ |
+ MY
+
+The object actually used is of the class L which allows you to
+override bits of MakeMaker inside your Makefile.PL by declaring
+MY::foo() methods.
+
+=head2 MakeMaker object hierarchy (real)
+
+Here's how it really works:
+
+ ExtUtils::MM_Any
+ |
+ ExtUtils::MM_Unix
+ |
+ ExtUtils::Liblist::Kid ExtUtils::MM_{Current OS} (if necessary)
+ | |
+ ExtUtils::Liblist ExtUtils::MakeMaker |
+ | | |
+ | | |-----------------------
+ ExtUtils::MM
+ | |
+ ExtUtils::MY MM (created by ExtUtils::MM)
+ | |
+ MY (created by ExtUtils::MY) |
+ . |
+ (mixin) |
+ . |
+ PACK### (created each call to ExtUtils::MakeMaker->new)
+
+NOTE: Yes, this is a mess. See
+L
+for some history.
+
+NOTE: When L is loaded it chooses a superclass for MM from
+amongst the ExtUtils::MM_* modules based on the current operating
+system.
+
+NOTE: ExtUtils::MM_{Current OS} represents one of the ExtUtils::MM_*
+modules except L chosen based on your operating system.
+
+NOTE: The main object used by MakeMaker is a PACK### object, *not*
+L. It is, effectively, a subclass of L,
+L, L and ExtUtils::MM_{Current OS}
+
+NOTE: The methods in L are simply copied into PACK### rather
+than MY being a superclass of PACK###. I don't remember the rationale.
+
+NOTE: L should be removed from the inheritance hiearchy
+and simply be called as functions.
+
+NOTE: Modules like L and L have been omitted for clarity.
+
+
+=head2 The MM_* hierarchy
+
+ MM_Win95 MM_NW5
+ \ /
+ MM_BeOS MM_Cygwin MM_OS2 MM_VMS MM_Win32 MM_DOS MM_UWIN
+ \ | | | / / /
+ ------------------------------------------------
+ | |
+ MM_Unix |
+ | |
+ MM_Any
+
+NOTE: Each direct L subclass is also an
+L subclass. This
+is a temporary hack because MM_Unix overrides some MM_Any methods with
+Unix specific code. It allows the non-Unix modules to see the
+original MM_Any implementations.
+
+NOTE: Modules like L and L have been omitted for clarity.
+
+=head1 PATCHING
+
+If you have a question you'd like to see added to the FAQ (whether or
+not you have the answer) please either:
+
+=over 2
+
+=item * make a pull request on the MakeMaker github repository
+
+=item * raise a issue on the MakeMaker github repository
+
+=item * file an RT ticket
+
+=item * email makemaker@perl.org
+
+=back
+
+=head1 AUTHOR
+
+The denizens of makemaker@perl.org.
+
+=head1 SEE ALSO
+
+L
+
+=cut
diff --git a/src/main/perl/lib/ExtUtils/MakeMaker/Locale.pm b/src/main/perl/lib/ExtUtils/MakeMaker/Locale.pm
new file mode 100644
index 000000000..5ec1eac89
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MakeMaker/Locale.pm
@@ -0,0 +1,384 @@
+package ExtUtils::MakeMaker::Locale;
+
+use strict;
+use warnings;
+our $VERSION = "7.78";
+$VERSION =~ tr/_//d;
+
+use base 'Exporter';
+our @EXPORT_OK = qw(
+ decode_argv env
+ $ENCODING_LOCALE $ENCODING_LOCALE_FS
+ $ENCODING_CONSOLE_IN $ENCODING_CONSOLE_OUT
+);
+
+use Encode ();
+use Encode::Alias ();
+
+our $ENCODING_LOCALE;
+our $ENCODING_LOCALE_FS;
+our $ENCODING_CONSOLE_IN;
+our $ENCODING_CONSOLE_OUT;
+
+sub DEBUG () { 0 }
+
+sub _init {
+ if ($^O eq "MSWin32") {
+ unless ($ENCODING_LOCALE) {
+ # Try to obtain what the Windows ANSI code page is
+ eval {
+ unless (defined &GetConsoleCP) {
+ require Win32;
+ # manually "import" it since Win32->import refuses
+ *GetConsoleCP = sub { &Win32::GetConsoleCP } if defined &Win32::GetConsoleCP;
+ }
+ unless (defined &GetConsoleCP) {
+ require Win32::API;
+ Win32::API->Import('kernel32', 'int GetConsoleCP()');
+ }
+ if (defined &GetConsoleCP) {
+ my $cp = GetConsoleCP();
+ $ENCODING_LOCALE = "cp$cp" if $cp;
+ }
+ };
+ }
+
+ unless ($ENCODING_CONSOLE_IN) {
+ # only test one since set together
+ unless (defined &GetInputCP) {
+ eval {
+ require Win32;
+ eval {
+ local $SIG{__WARN__} = sub {} if ( "$]" < 5.014 ); # suppress deprecation warning for inherited AUTOLOAD of Win32::GetConsoleCP()
+ Win32::GetConsoleCP();
+ };
+ # manually "import" it since Win32->import refuses
+ *GetInputCP = sub { &Win32::GetConsoleCP } if defined &Win32::GetConsoleCP;
+ *GetOutputCP = sub { &Win32::GetConsoleOutputCP } if defined &Win32::GetConsoleOutputCP;
+ };
+ unless (defined &GetInputCP) {
+ eval {
+ # try Win32::Console module for codepage to use
+ require Win32::Console;
+ *GetInputCP = sub { &Win32::Console::InputCP }
+ if defined &Win32::Console::InputCP;
+ *GetOutputCP = sub { &Win32::Console::OutputCP }
+ if defined &Win32::Console::OutputCP;
+ };
+ }
+ unless (defined &GetInputCP) {
+ # final fallback
+ *GetInputCP = *GetOutputCP = sub {
+ # another fallback that could work is:
+ # reg query HKLM\System\CurrentControlSet\Control\Nls\CodePage /v ACP
+ ((qx(chcp) || '') =~ /^Active code page: (\d+)/)
+ ? $1 : ();
+ };
+ }
+ }
+ my $cp = GetInputCP();
+ $ENCODING_CONSOLE_IN = "cp$cp" if $cp;
+ $cp = GetOutputCP();
+ $ENCODING_CONSOLE_OUT = "cp$cp" if $cp;
+ }
+ }
+
+ unless ($ENCODING_LOCALE) {
+ eval {
+ require I18N::Langinfo;
+ $ENCODING_LOCALE = I18N::Langinfo::langinfo(I18N::Langinfo::CODESET());
+
+ # Workaround of Encode < v2.25. The "646" encoding alias was
+ # introduced in Encode-2.25, but we don't want to require that version
+ # quite yet. Should avoid the CPAN testers failure reported from
+ # openbsd-4.7/perl-5.10.0 combo.
+ $ENCODING_LOCALE = "ascii" if $ENCODING_LOCALE eq "646";
+
+ # https://rt.cpan.org/Ticket/Display.html?id=66373
+ $ENCODING_LOCALE = "hp-roman8" if $^O eq "hpux" && $ENCODING_LOCALE eq "roman8";
+ };
+ $ENCODING_LOCALE ||= $ENCODING_CONSOLE_IN;
+ }
+
+ # Workaround of Encode < v2.71 for "cp65000" and "cp65001"
+ # The "cp65000" and "cp65001" aliases were added in [Encode v2.71](https://github.com/dankogai/p5-encode/commit/7874bd95aa10967a3b5dbae333d16bcd703ac6c6)
+ # via commit .
+ # This will avoid test failures for Win32 machines using the UTF-7 or UTF-8 code pages.
+ $ENCODING_LOCALE = 'UTF-7' if $ENCODING_LOCALE && lc($ENCODING_LOCALE) eq "cp65000";
+ $ENCODING_LOCALE = 'utf-8-strict' if $ENCODING_LOCALE && lc($ENCODING_LOCALE) eq "cp65001";
+
+ if ($^O eq "darwin") {
+ $ENCODING_LOCALE_FS ||= "UTF-8";
+ }
+
+ # final fallback
+ $ENCODING_LOCALE ||= $^O eq "MSWin32" ? "cp1252" : "UTF-8";
+ $ENCODING_LOCALE_FS ||= $ENCODING_LOCALE;
+ $ENCODING_CONSOLE_IN ||= $ENCODING_LOCALE;
+ $ENCODING_CONSOLE_OUT ||= $ENCODING_CONSOLE_IN;
+
+ unless (Encode::find_encoding($ENCODING_LOCALE)) {
+ my $foundit;
+ if (lc($ENCODING_LOCALE) eq "gb18030") {
+ eval {
+ require Encode::HanExtra;
+ };
+ if ($@) {
+ die "Need Encode::HanExtra to be installed to support locale codeset ($ENCODING_LOCALE), stopped";
+ }
+ $foundit++ if Encode::find_encoding($ENCODING_LOCALE);
+ }
+ die "The locale codeset ($ENCODING_LOCALE) isn't one that perl can decode, stopped"
+ unless $foundit;
+
+ }
+
+ # use Data::Dump; ddx $ENCODING_LOCALE, $ENCODING_LOCALE_FS, $ENCODING_CONSOLE_IN, $ENCODING_CONSOLE_OUT;
+}
+
+_init();
+Encode::Alias::define_alias(sub {
+ no strict 'refs';
+ no warnings 'once';
+ return ${"ENCODING_" . uc(shift)};
+}, "locale");
+
+sub _flush_aliases {
+ no strict 'refs';
+ for my $a (sort keys %Encode::Alias::Alias) {
+ if (defined ${"ENCODING_" . uc($a)}) {
+ delete $Encode::Alias::Alias{$a};
+ warn "Flushed alias cache for $a" if DEBUG;
+ }
+ }
+}
+
+sub reinit {
+ $ENCODING_LOCALE = shift;
+ $ENCODING_LOCALE_FS = shift;
+ $ENCODING_CONSOLE_IN = $ENCODING_LOCALE;
+ $ENCODING_CONSOLE_OUT = $ENCODING_LOCALE;
+ _init();
+ _flush_aliases();
+}
+
+sub decode_argv {
+ die if defined wantarray;
+ for (@ARGV) {
+ $_ = Encode::decode(locale => $_, @_);
+ }
+}
+
+sub env {
+ my $k = Encode::encode(locale => shift);
+ my $old = $ENV{$k};
+ if (@_) {
+ my $v = shift;
+ if (defined $v) {
+ $ENV{$k} = Encode::encode(locale => $v);
+ }
+ else {
+ delete $ENV{$k};
+ }
+ }
+ return Encode::decode(locale => $old) if defined wantarray;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+ExtUtils::MakeMaker::Locale - bundled Encode::Locale
+
+=head1 SYNOPSIS
+
+ use Encode::Locale;
+ use Encode;
+
+ $string = decode(locale => $bytes);
+ $bytes = encode(locale => $string);
+
+ if (-t) {
+ binmode(STDIN, ":encoding(console_in)");
+ binmode(STDOUT, ":encoding(console_out)");
+ binmode(STDERR, ":encoding(console_out)");
+ }
+
+ # Processing file names passed in as arguments
+ my $uni_filename = decode(locale => $ARGV[0]);
+ open(my $fh, "<", encode(locale_fs => $uni_filename))
+ || die "Can't open '$uni_filename': $!";
+ binmode($fh, ":encoding(locale)");
+ ...
+
+=head1 DESCRIPTION
+
+In many applications it's wise to let Perl use Unicode for the strings it
+processes. Most of the interfaces Perl has to the outside world are still byte
+based. Programs therefore need to decode byte strings that enter the program
+from the outside and encode them again on the way out.
+
+The POSIX locale system is used to specify both the language conventions
+requested by the user and the preferred character set to consume and
+output. The C module looks up the charset and encoding (called
+a CODESET in the locale jargon) and arranges for the L module to know
+this encoding under the name "locale". It means bytes obtained from the
+environment can be converted to Unicode strings by calling C<<
+Encode::encode(locale => $bytes) >> and converted back again with C<<
+Encode::decode(locale => $string) >>.
+
+Where file systems interfaces pass file names in and out of the program we also
+need care. The trend is for operating systems to use a fixed file encoding
+that don't actually depend on the locale; and this module determines the most
+appropriate encoding for file names. The L module will know this
+encoding under the name "locale_fs". For traditional Unix systems this will
+be an alias to the same encoding as "locale".
+
+For programs running in a terminal window (called a "Console" on some systems)
+the "locale" encoding is usually a good choice for what to expect as input and
+output. Some systems allows us to query the encoding set for the terminal and
+C will do that if available and make these encodings known
+under the C aliases "console_in" and "console_out". For systems where
+we can't determine the terminal encoding these will be aliased as the same
+encoding as "locale". The advice is to use "console_in" for input known to
+come from the terminal and "console_out" for output to the terminal.
+
+In addition to arranging for various Encode aliases the following functions and
+variables are provided:
+
+=over
+
+=item decode_argv( )
+
+=item decode_argv( Encode::FB_CROAK )
+
+This will decode the command line arguments to perl (the C<@ARGV> array) in-place.
+
+The function will by default replace characters that can't be decoded by
+"\x{FFFD}", the Unicode replacement character.
+
+Any argument provided is passed as CHECK to underlying Encode::decode() call.
+Pass the value C to have the decoding croak if not all the
+command line arguments can be decoded. See L
+for details on other options for CHECK.
+
+=item env( $uni_key )
+
+=item env( $uni_key => $uni_value )
+
+Interface to get/set environment variables. Returns the current value as a
+Unicode string. The $uni_key and $uni_value arguments are expected to be
+Unicode strings as well. Passing C as $uni_value deletes the
+environment variable named $uni_key.
+
+The returned value will have the characters that can't be decoded replaced by
+"\x{FFFD}", the Unicode replacement character.
+
+There is no interface to request alternative CHECK behavior as for
+decode_argv(). If you need that you need to call encode/decode yourself.
+For example:
+
+ my $key = Encode::encode(locale => $uni_key, Encode::FB_CROAK);
+ my $uni_value = Encode::decode(locale => $ENV{$key}, Encode::FB_CROAK);
+
+=item reinit( )
+
+=item reinit( $encoding )
+
+Reinitialize the encodings from the locale. You want to call this function if
+you changed anything in the environment that might influence the locale.
+
+This function will croak if the determined encoding isn't recognized by
+the Encode module.
+
+With argument force $ENCODING_... variables to set to the given value.
+
+=item $ENCODING_LOCALE
+
+The encoding name determined to be suitable for the current locale.
+L know this encoding as "locale".
+
+=item $ENCODING_LOCALE_FS
+
+The encoding name determined to be suitable for file system interfaces
+involving file names.
+L know this encoding as "locale_fs".
+
+=item $ENCODING_CONSOLE_IN
+
+=item $ENCODING_CONSOLE_OUT
+
+The encodings to be used for reading and writing output to the a console.
+L know these encodings as "console_in" and "console_out".
+
+=back
+
+=head1 NOTES
+
+This table summarizes the mapping of the encodings set up
+by the C module:
+
+ Encode | | |
+ Alias | Windows | Mac OS X | POSIX
+ ------------+---------+--------------+------------
+ locale | ANSI | nl_langinfo | nl_langinfo
+ locale_fs | ANSI | UTF-8 | nl_langinfo
+ console_in | OEM | nl_langinfo | nl_langinfo
+ console_out | OEM | nl_langinfo | nl_langinfo
+
+=head2 Windows
+
+Windows has basically 2 sets of APIs. A wide API (based on passing UTF-16
+strings) and a byte based API based a character set called ANSI. The
+regular Perl interfaces to the OS currently only uses the ANSI APIs.
+Unfortunately ANSI is not a single character set.
+
+The encoding that corresponds to ANSI varies between different editions of
+Windows. For many western editions of Windows ANSI corresponds to CP-1252
+which is a character set similar to ISO-8859-1. Conceptually the ANSI
+character set is a similar concept to the POSIX locale CODESET so this module
+figures out what the ANSI code page is and make this available as
+$ENCODING_LOCALE and the "locale" Encoding alias.
+
+Windows systems also operate with another byte based character set.
+It's called the OEM code page. This is the encoding that the Console
+takes as input and output. It's common for the OEM code page to
+differ from the ANSI code page.
+
+=head2 Mac OS X
+
+On Mac OS X the file system encoding is always UTF-8 while the locale
+can otherwise be set up as normal for POSIX systems.
+
+File names on Mac OS X will at the OS-level be converted to
+NFD-form. A file created by passing a NFC-filename will come
+in NFD-form from readdir(). See L for details
+of NFD/NFC.
+
+Actually, Apple does not follow the Unicode NFD standard since not all
+character ranges are decomposed. The claim is that this avoids problems with
+round trip conversions from old Mac text encodings. See L for
+details.
+
+=head2 POSIX (Linux and other Unixes)
+
+File systems might vary in what encoding is to be used for
+filenames. Since this module has no way to actually figure out
+what the is correct it goes with the best guess which is to
+assume filenames are encoding according to the current locale.
+Users are advised to always specify UTF-8 as the locale charset.
+
+=head1 SEE ALSO
+
+L, L, L
+
+=head1 AUTHOR
+
+Copyright 2010 Gisle Aas .
+
+This library is free software; you can redistribute it and/or
+modify it under the same terms as Perl itself.
+
+=cut
diff --git a/src/main/perl/lib/ExtUtils/MakeMaker/Tutorial.pod b/src/main/perl/lib/ExtUtils/MakeMaker/Tutorial.pod
new file mode 100644
index 000000000..b46e6630f
--- /dev/null
+++ b/src/main/perl/lib/ExtUtils/MakeMaker/Tutorial.pod
@@ -0,0 +1,213 @@
+package ExtUtils::MakeMaker::Tutorial;
+
+our $VERSION = '7.78';
+$VERSION =~ tr/_//d;
+
+
+=head1 NAME
+
+ExtUtils::MakeMaker::Tutorial - Writing a module with MakeMaker
+
+=head1 SYNOPSIS
+
+ use ExtUtils::MakeMaker;
+
+ WriteMakefile(
+ NAME => 'Your::Module',
+ VERSION_FROM => 'lib/Your/Module.pm'
+ );
+
+=head1 DESCRIPTION
+
+This is a short tutorial on writing a simple module with MakeMaker.
+It's really not that hard.
+
+
+=head2 The Mantra
+
+MakeMaker modules are installed using this simple mantra
+
+ perl Makefile.PL
+ make
+ make test
+ make install
+
+There are lots more commands and options, but the above will do it.
+
+
+=head2 The Layout
+
+The basic files in a module look something like this.
+
+ Makefile.PL
+ MANIFEST
+ lib/Your/Module.pm
+
+That's all that's strictly necessary. There's additional files you might
+want:
+
+ lib/Your/Other/Module.pm
+ t/some_test.t
+ t/some_other_test.t
+ Changes
+ README
+ INSTALL
+ MANIFEST.SKIP
+ bin/some_program
+
+=over 4
+
+=item Makefile.PL
+
+When you run Makefile.PL, it makes a Makefile. That's the whole point of
+MakeMaker. The Makefile.PL is a simple program which loads
+ExtUtils::MakeMaker and runs the WriteMakefile() function to generate a
+Makefile.
+
+Here's an example of what you need for a simple module:
+
+ use ExtUtils::MakeMaker;
+
+ WriteMakefile(
+ NAME => 'Your::Module',
+ VERSION_FROM => 'lib/Your/Module.pm'
+ );
+
+NAME is the top-level namespace of your module. VERSION_FROM is the file
+which contains the $VERSION variable for the entire distribution. Typically
+this is the same as your top-level module.
+
+
+=item MANIFEST
+
+A simple listing of all the files in your distribution.
+
+ Makefile.PL
+ MANIFEST
+ lib/Your/Module.pm
+
+File paths in a MANIFEST always use Unix conventions (ie. /) even if you're
+not on Unix.
+
+You can write this by hand or generate it with 'make manifest'.
+
+See L for more details.
+
+
+=item lib/
+
+This is the directory where the .pm and .pod files you wish to have
+installed go. They are laid out according to namespace. So Foo::Bar
+is F.
+
+
+=item t/
+
+Tests for your modules go here. Each test filename ends with a .t.
+So F 'make test' will run these tests.
+
+Typically, the F test directory is flat, with all test files located
+directly within it. However, you can nest tests within subdirectories, for
+example:
+
+ t/foo/subdir_test.t
+
+To do this, you need to inform C in your I file
+in the following fashion:
+
+ test => {TESTS => 't/*.t t/*/*.t'}
+
+That will run all tests in F , as well as all tests in all subdirectories
+that reside under F . You can nest as deeply as makes sense for your project.
+Simply add another entry in the test location string. For example, to test:
+
+ t/foo/bar/subdir_test.t
+
+You would use the following C directive:
+
+ test => {TESTS => 't/*.t t/*/*/*.t'}
+
+Note that in the above example, tests in the first subdirectory will not be
+run. To run all tests in the intermediary subdirectory preceding the one
+the test files are in, you need to explicitly note it:
+
+ test => {TESTS => 't/*.t t/*/*.t t/*/*/*.t'}
+
+You don't need to specify wildcards if you only want to test within specific
+subdirectories. The following example will only run tests in F:
+
+ test => {TESTS => 't/foo/*.t'}
+
+Tests are run from the top level of your distribution. So inside a test
+you would refer to ./lib to enter the lib directory, for example.
+
+
+=item Changes
+
+A log of changes you've made to this module. The layout is free-form.
+Here's an example:
+
+ 1.01 Fri Apr 11 00:21:25 PDT 2003
+ - thing() does some stuff now
+ - fixed the wiggy bug in withit()
+
+ 1.00 Mon Apr 7 00:57:15 PDT 2003
+ - "Rain of Frogs" now supported
+
+
+=item README
+
+A short description of your module, what it does, why someone would use it
+and its limitations. CPAN automatically pulls your README file out of
+the archive and makes it available to CPAN users, it is the first thing
+they will read to decide if your module is right for them.
+
+
+=item INSTALL
+
+Instructions on how to install your module along with any dependencies.
+Suggested information to include here:
+
+ any extra modules required for use
+ the minimum version of Perl required
+ if only works on certain operating systems
+
+
+=item MANIFEST.SKIP
+
+A file full of regular expressions to exclude when using 'make
+manifest' to generate the MANIFEST. These regular expressions
+are checked against each file path found in the distribution (so
+you're matching against "t/foo.t" not "foo.t").
+
+Here's a sample:
+
+ ~$ # ignore emacs and vim backup files
+ .bak$ # ignore manual backups
+ \# # ignore CVS old revision files and emacs temp files
+
+Since # can be used for comments, # must be escaped.
+
+MakeMaker comes with a default MANIFEST.SKIP to avoid things like
+version control directories and backup files. Specifying your own
+will override this default.
+
+
+=item bin/
+
+
+=back
+
+=head1 SEE ALSO
+
+L gives stylistic help writing a module.
+
+L