Skip to content

Commit 1523041

Browse files
Fix utf8::valid() for CPAN::Meta parsing (#346)
* Fix utf8::valid() to properly check string validity The previous implementation used CharsetDetector which was incorrect: - It converted the string to bytes using default charset - Then tried to detect if those bytes were UTF-8 - This always failed for properly decoded strings The new implementation correctly checks: - For character strings (UTF-8 flag on): validates surrogate pairs - For byte strings (UTF-8 flag off): decodes bytes as UTF-8 This fixes CPAN::Meta::YAML parsing which was failing with: "Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set)" The error occurred because CPAN::Meta::YAML checks: if (utf8::is_utf8($string) && !utf8::valid($string)) and utf8::valid() was always returning false. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Document utf8::valid() fix in cpan_client.md (Phase 16) Added documentation for the fix that resolved CPAN::Meta::YAML parsing errors that were preventing proper test dependency detection. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix MYMETA.yml format and create jcpan DateTime fix plan 1. ExtUtils/MakeMaker.pm: Generate meta-spec v2 format MYMETA.yml - Test dependencies now properly detected by CPAN.pm - Uses nested prereqs structure instead of flat v1.4 format 2. dev/design/JCPAN_DATETIME_FIXES.md: Comprehensive fix plan - Documents all errors from clean cache DateTime install - Prioritized implementation plan - Critical: File::stat.pm needed for DateTime::Locale Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Add Class::Struct and File::stat via import system; document JVM VerifyError Phase 17 DateTime fixes: - Import Class::Struct.pm from perl5/lib (required by File::stat) - Import File::stat.pm from perl5/lib (required by File::ShareDir::Install) - Document JVM VerifyError with minimal reproducer File::stat triggers a JVM bytecode verification error due to a bug when compiling: no strict 'refs' + for loop + defined eval { &{symbolic_ref} } Minimal reproducer: no strict 'refs'; for (qw(X Y Z)) { defined eval { &{"Fcntl::S_IF$_"} } } Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update JVM VerifyError analysis with simpler reproducer and root cause The minimal reproducer doesn't require a for loop: no strict 'refs'; my $result = defined eval { &{"Fcntl::S_IFX"} }; Root cause: The block dispatcher stores ordinal in controlFlowActionSlot, but different code paths merge at a label with inconsistent types for that slot (integer vs TOP). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix VerifyError in eval block control flow handling When a subroutine call inside an eval block returns a control flow marker (LAST/NEXT/REDO), the control flow dispatch code for unlabeled LAST/NEXT was jumping to target labels with an empty operand stack, but the merge point expected a RuntimeList on the stack. This caused a JVM VerifyError ("Inconsistent stackmap frames") when loading File::stat.pm or other modules that use the pattern: eval { &{"Fcntl::S_IFX"} } The fix pushes the control flow marker onto the stack before jumping to the merge point, ensuring consistent stack state at all paths. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update design doc: JVM VerifyError fix completed Document the root cause analysis and fix for Issue #11 (VerifyError when loading File::stat.pm. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> EOF ) * Add missing S_* mode constants to Fcntl.pm File::stat.pm requires S_IRUSR, S_IWUSR, S_IXUSR and other mode constants from Fcntl. These were listed in @EXPORT_OK but never actually defined. Added: - File type masks: S_IFMT, S_IFREG, S_IFDIR, S_IFLNK, etc. - Special mode bits: S_ISUID, S_ISGID, S_ISVTX - User permissions: S_IRUSR, S_IWUSR, S_IXUSR, S_IRWXU - Group permissions: S_IRGRP, S_IWGRP, S_IXGRP, S_IRWXG - Other permissions: S_IROTH, S_IWOTH, S_IXOTH, S_IRWXO - File type test functions: S_ISREG, S_ISDIR, S_ISLNK, etc. - Permission extraction: S_IMODE Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update design doc: File::stat.pm now loads successfully Both the JVM VerifyError and the missing Fcntl constants have been fixed. File::stat.pm now loads and works correctly. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix require bareword handling with CORE::GLOBAL::require override When CORE::GLOBAL::require is overridden and a module uses 'require Bareword;' under strict subs, the bareword was incorrectly flagged as a strict subs violation. Root cause: When the parser detected a CORE::GLOBAL::require override, it rewrote the require call to a subroutine call, but the bareword argument (e.g., 'Exporter') was parsed as an expression instead of using require's special bareword-to-filename conversion. Fix: Added special handling in ParsePrimary.java for 'require' when CORE::GLOBAL::require is overridden: 1. Parse the argument using standard require handling (converts bareword to filename) 2. Build a subroutine call node with the &CORE::GLOBAL::require code ref Also added Exporter::require_version() method which delegates to UNIVERSAL::VERSION for historical compatibility with older Exporter usage. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update JCPAN_DATETIME_FIXES.md with completed fixes - Marked Exporter::require_version as FIXED - Marked CORE::GLOBAL::require bareword handling as FIXED - Updated progress tracking section Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix Exporter version check in import arguments When calling Module->import('0.03', 'symbol'), Perl's Exporter treats arguments starting with a digit as version checks, not symbols to export. Added this logic to the Java Exporter: 1. If symbol starts with digit, call $pkg->VERSION($version) 2. If version was only argument, import from @export 3. If version + empty string ('use Foo 1.23, ""'), import nothing 4. Otherwise skip version and continue with other imports This fixes: 'Symbol 0.03 not allowed for export in package File::ShareDir::Install' Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix MakeMaker $(INST_LIB) variable expansion When Makefile.PL scripts provide an explicit PM hash with Make-style variables like $(INST_LIB)/Module.pm, expand them to actual paths. Without this fix, modules would be installed to a literal '$(INST_LIB)' directory instead of the actual install base. This fixes Class::Inspector and similar modules using explicit PM hashes. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Update design doc: jcpan DateTime installation complete All blocking issues have been fixed: - Exporter version check in import arguments - MakeMaker $(INST_LIB) variable expansion jcpan install DateTime now works successfully. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Add File::ShareDir::Install support to MakeMaker When Makefile.PL uses File::ShareDir::Install to register share directories (via install_share()), our MakeMaker now processes @file::ShareDir::Install::DIRS and copies those files to the proper location under auto/share/dist/<DistName>/. This enables DateTime::Locale to work correctly, as it uses share files for locale data (1070 .pl files for different locales). Test: jcpan install DateTime::Locale now installs all locale data files. Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix IPC::Open3 redirection directive handling When open3() is called with redirection directives like '>&STDERR', they are read-only strings that cannot be modified. This fix: 1. In IPCOpen3.java: - Added isOutputRedirection() and isInputRedirection() to detect >&/&< directives - Added handleOutputRedirection() to pipe process output to named handles - Added isUsableHandle() to properly detect undef handles (not just reference-to-undef) - Added getStringValue() to properly dereference scalar references 2. In Open3.pm: - Check for redirection directives before trying to update caller's variables - Skip assignment to $_[N] when it's a redirection directive (read-only) This fixes: 'open3: Modification of a read-only value attempted' errors in tests like t/00-compile.t that use open3($stdin, '>&STDERR', $stderr, ...). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
1 parent ff238cc commit 1523041

14 files changed

Lines changed: 1808 additions & 32 deletions

File tree

dev/design/JCPAN_DATETIME_FIXES.md

Lines changed: 311 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,311 @@
1+
# jcpan DateTime Fix Plan
2+
3+
## Overview
4+
5+
This document tracks all errors and warnings that occur when running `jcpan install DateTime` with a clean cache, and the plan to fix them.
6+
7+
## Error Categories
8+
9+
### 1. CRITICAL: DateTime::Locale Installation Fails
10+
11+
**Root Cause**: `File::stat.pm` is missing
12+
13+
```
14+
Can't locate File/stat.pm in @INC at /Users/fglock/.perlonjava/lib/File/ShareDir/Install.pm line 11
15+
```
16+
17+
**Impact**: DateTime::Locale cannot be configured, which means DateTime tests fail with:
18+
```
19+
Can't locate DateTime/Locale.pm in @INC
20+
```
21+
22+
**Solution**: Implement `File::stat.pm` - a stub or full implementation
23+
24+
**Priority**: HIGH
25+
26+
---
27+
28+
### 2. IPC::Open3 Read-Only Modification Error
29+
30+
**Error**:
31+
```
32+
open3: Modification of a read-only value attempted
33+
at IPCOpen3.java line 162
34+
```
35+
36+
**Impact**: Many module tests fail in `t/00-compile.t` type tests that use open3 to test module compilation
37+
38+
**Solution**: Fix IPCOpen3.java line 162 to handle read-only values
39+
40+
**Priority**: MEDIUM
41+
42+
---
43+
44+
### 3. Missing Core Modules
45+
46+
| Module | Used By | Priority |
47+
|--------|---------|----------|
48+
| File::stat | File::ShareDir::Install | HIGH |
49+
| IO::Select | Various | MEDIUM |
50+
| PerlIO::encoding | Encode tests | LOW |
51+
| encoding.pm | Encode | LOW |
52+
53+
---
54+
55+
### 4. Encode Module Issues
56+
57+
**Errors**:
58+
```
59+
Can't locate object method "decode" via package "ISO-8859-1"
60+
Can't locate object method "encode" via package "UTF-8"
61+
Can't locate object method "encodings" via package "Encode"
62+
Undefined subroutine &Encode::define_encoding called
63+
```
64+
65+
**Root Cause**: Encode is an XS module; PerlOnJava has a Java implementation but some methods are missing
66+
67+
**Solution**: Add missing methods to Encode.java:
68+
- `encodings()`
69+
- Ensure `decode`/`encode` work with encoding names as package names
70+
71+
**Priority**: MEDIUM
72+
73+
---
74+
75+
### 5. Version Format Errors
76+
77+
**Error**:
78+
```
79+
Invalid version format (version required) at Version.java line 334
80+
```
81+
82+
**Solution**: Handle edge cases in Version.java
83+
84+
**Priority**: LOW
85+
86+
---
87+
88+
### 6. CPAN::Meta::Requirements Warning
89+
90+
**Error**:
91+
```
92+
Use of uninitialized value in numeric gt (>) at jar:PERL5LIB/CPAN/Meta/Requirements.pm line 215
93+
```
94+
95+
**Solution**: Check for undef before numeric comparison
96+
97+
**Priority**: LOW
98+
99+
---
100+
101+
### 7. Test::Builder Overload Issue
102+
103+
**Error**:
104+
```
105+
Undefined subroutine &*version::("" called at jar:PERL5LIB/Test/Builder.pm line 771
106+
```
107+
108+
**Solution**: Fix overload handling for version objects
109+
110+
**Priority**: LOW
111+
112+
---
113+
114+
### 8. Exporter require_version Missing [FIXED]
115+
116+
**Error**:
117+
```
118+
Can't locate object method "require_version" via package "Testing"
119+
```
120+
121+
**Solution**: Added `require_version` method to Java `Exporter.java` which delegates to `UNIVERSAL::VERSION`
122+
123+
**Files changed**:
124+
- `src/main/java/org/perlonjava/runtime/perlmodule/Exporter.java`
125+
126+
**Priority**: MEDIUM - **FIXED** (commit 70ce06938)
127+
128+
---
129+
130+
### 9. Too Many Arguments for like()
131+
132+
**Error**:
133+
```
134+
Too many arguments for main::like at t/conflicts.t line 109
135+
```
136+
137+
**Root Cause**: Test::More's `like()` has different prototype handling
138+
139+
**Priority**: LOW (cosmetic test failure)
140+
141+
---
142+
143+
### 10. Carp.pm Bareword Error with CORE::GLOBAL::require [FIXED]
144+
145+
**Error**:
146+
```
147+
Bareword "Exporter" not allowed while "strict subs" in use at jar:PERL5LIB/Carp.pm line 224
148+
```
149+
150+
**Root Cause**: When `CORE::GLOBAL::require` is overridden and a module uses `require Bareword;` under strict subs, the bareword was parsed as an expression instead of using require's special bareword-to-filename conversion.
151+
152+
**Solution**: Added special handling in `ParsePrimary.java` for `require` when `CORE::GLOBAL::require` is overridden:
153+
1. Parse the argument using standard require handling (converts bareword to filename string)
154+
2. Build a subroutine call node with `&CORE::GLOBAL::require(...)` form
155+
156+
**Files changed**:
157+
- `src/main/java/org/perlonjava/frontend/parser/ParsePrimary.java`
158+
159+
**Priority**: MEDIUM - **FIXED** (commit 70ce06938)
160+
161+
---
162+
163+
### 11. JVM VerifyError: Inconsistent Stackmap Frames [FIXED]
164+
165+
**Error**:
166+
```
167+
java.lang.VerifyError: Inconsistent stackmap frames at branch target 518
168+
Exception Details:
169+
Location:
170+
org/perlonjava/anon195.apply(...) @507: goto
171+
Reason:
172+
Current frame's stack size doesn't match stackmap.
173+
```
174+
175+
**Triggered by**: perl5's `File/stat.pm` (imported via sync.pl)
176+
177+
**Minimal Reproducer**:
178+
```perl
179+
no strict "refs";
180+
my $result = defined eval { &{"Fcntl::S_IFX"} };
181+
```
182+
183+
The issue requires BOTH of these:
184+
1. `no strict "refs"` in scope (enables symbolic subroutine calls)
185+
2. `defined eval { &{"symbolic_ref"} }` (eval-wrapped symbolic sub call with defined check)
186+
187+
**Works** (any element missing):
188+
- `eval { &{"..."} }` without `defined` - OK
189+
- `defined eval { die "x" }` - OK (no symbolic ref call)
190+
- `defined eval { Func() }` - OK (direct call, not symbolic)
191+
- With `use strict "refs"` - OK (throws error at compile time)
192+
193+
**Root Cause Analysis**: The bytecode generator in `EmitVariable.java` creates inconsistent stack states when handling control flow markers from subroutine calls inside eval blocks.
194+
195+
When `&{"symbolic_ref"}` is called:
196+
1. `RuntimeCode.apply()` may return a `RuntimeControlFlowList` marker (LAST/NEXT/REDO)
197+
2. The code checks `isNonLocalGoto()` and branches to handle the marker
198+
3. For unlabeled LAST/NEXT, the original code jumped directly to loop labels with an **empty stack**
199+
4. But the `applyNoControlFlow` merge point expects a **RuntimeList on the stack** (from DUP or cfSlot load)
200+
5. JVM frame computation fails because paths arriving at merge point have different stack states
201+
202+
**Specific bytecode issue** (from disassembly before fix):
203+
```
204+
L9 checkUnlabeled
205+
ILOAD 29; ICONST_0; IF_ICMPEQ L11 // LAST?
206+
ILOAD 29; ICONST_1; IF_ICMPEQ L12 // NEXT?
207+
ILOAD 29; ICONST_2; IF_ICMPEQ L13 // REDO?
208+
GOTO L8
209+
L11 GOTO L7 // LAST: empty stack, jumps to L7
210+
L12 GOTO L7 // NEXT: empty stack, jumps to L7
211+
L13 GOTO L6 // REDO: OK, goes to redo label
212+
L8 ALOAD 27 // Load cfSlot, falls through to L7
213+
L7 FRAME [...] [RuntimeList] // Expects value on stack!
214+
ASTORE 25
215+
```
216+
217+
**Fix** (commit 280d03af2): Push the control flow marker (from cfSlot) onto the stack before jumping to the merge point:
218+
```java
219+
mv.visitLabel(isLast);
220+
mv.visitVarInsn(Opcodes.ALOAD, cfSlot); // Push marker
221+
mv.visitJumpInsn(Opcodes.GOTO, applyNoControlFlow);
222+
223+
mv.visitLabel(isNext);
224+
mv.visitVarInsn(Opcodes.ALOAD, cfSlot); // Push marker
225+
mv.visitJumpInsn(Opcodes.GOTO, applyNoControlFlow);
226+
```
227+
228+
**Files changed**:
229+
- `src/main/java/org/perlonjava/backend/jvm/EmitVariable.java` lines 710-721
230+
231+
**Impact**: File::stat.pm and other modules using `eval { &{...} }` pattern now load correctly.
232+
233+
**Priority**: HIGH (blocks File::stat and potentially other complex modules) - **FIXED**
234+
235+
---
236+
237+
## Implementation Plan
238+
239+
### Phase 1: Critical (enables DateTime to install)
240+
241+
1. **Fix JVM VerifyError for complex control flow** (Issue #11)
242+
- Debug why File::stat.pm causes stackmap frame inconsistency
243+
- Create minimal reproduction case
244+
- Fix bytecode emitter
245+
- Files: `EmitterMethodCreator.java`, `EmitterVisitor.java`, `EmitControlFlow.java`
246+
247+
2. **Implement File::stat.pm stub** (if JVM fix takes too long)
248+
- Create `src/main/perl/lib/File/stat.pm`
249+
- Implement basic stat() wrapper returning object with standard fields
250+
- File: `src/main/perl/lib/File/stat.pm`
251+
252+
### Phase 2: High Priority (reduces test failures)
253+
254+
2. **Fix IPC::Open3 read-only error**
255+
- File: `src/main/java/org/perlonjava/runtime/perlmodule/IPCOpen3.java`
256+
- Line 162: clone value before modification
257+
258+
3. **Add Encode::encodings() method**
259+
- File: `src/main/java/org/perlonjava/runtime/perlmodule/Encode.java`
260+
261+
4. **Implement require_version in UNIVERSAL**
262+
- File: `src/main/java/org/perlonjava/runtime/perlmodule/Universal.java`
263+
264+
### Phase 3: Medium Priority
265+
266+
5. **Fix Version.java edge cases**
267+
6. **Fix CPAN::Meta::Requirements undef check**
268+
7. **Implement IO::Select stub**
269+
270+
### Phase 4: Low Priority (polish)
271+
272+
8. **Fix Test::Builder overload handling**
273+
9. **Fix Carp.pm bareword issue**
274+
10. **Fix like() prototype handling**
275+
276+
---
277+
278+
## Progress Tracking
279+
280+
### Completed
281+
- [x] Phase 16: utf8::valid() fix for CPAN::Meta parsing (2026-03-20)
282+
- [x] ExtUtils::MakeMaker MYMETA.yml meta-spec v2 format (2026-03-20)
283+
- [x] Added File::stat.pm via import system (2026-03-20) - but triggers JVM bug
284+
- [x] JVM VerifyError fix for eval block control flow (2026-03-20, commit 280d03af2)
285+
- [x] Add missing S_* mode constants to Fcntl.pm (2026-03-20, commit 94974ba79)
286+
- File::stat.pm now loads successfully
287+
- [x] Exporter::require_version() implementation (2026-03-20, commit 70ce06938)
288+
- [x] CORE::GLOBAL::require bareword handling fix (2026-03-20, commit 70ce06938)
289+
- [x] Exporter version check in import (2026-03-21, commit a2e0aa131)
290+
- First argument starting with digit is now treated as version check
291+
- Fixes: "Symbol 0.03 not allowed for export in package File::ShareDir::Install"
292+
- [x] MakeMaker $(INST_LIB) variable expansion (2026-03-21, commit f42f9125c)
293+
- Fixes modules with explicit PM hash using Make-style variables
294+
295+
### In Progress
296+
- None
297+
298+
### All fixes complete!
299+
- `jcpan install DateTime` works successfully
300+
- DateTime module loads and functions correctly:
301+
```
302+
./jperl -e 'use DateTime; print DateTime->now->strftime("%Y-%m-%d")'
303+
2026-03-21
304+
```
305+
306+
---
307+
308+
## Related Documents
309+
310+
- `dev/design/cpan_client.md` - Main CPAN client documentation
311+
- `dev/design/xsloader.md` - XSLoader implementation

dev/design/cpan_client.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,58 @@ All major DateTime issues have been fixed. The 7 remaining test failures are:
355355

356356
---
357357

358+
## Phase 16: utf8::valid() Fix for CPAN::Meta Parsing (2026-03-20)
359+
360+
### Problem Statement
361+
362+
When installing DateTime with empty caches, CPAN::Meta::YAML parsing would fail with:
363+
```
364+
Read an invalid UTF-8 string (maybe mixed UTF-8 and 8-bit character set).
365+
Did you decode with lax ":utf8" instead of strict ":encoding(UTF-8)"?
366+
```
367+
368+
This error prevented proper parsing of META.yml/MYMETA.yml files, which meant test dependencies like Test::Without::Module and CPAN::Meta::Check were not being properly detected.
369+
370+
### Root Cause
371+
372+
CPAN::Meta::YAML validates strings before parsing:
373+
```perl
374+
if ( utf8::is_utf8($string) && ! utf8::valid($string) ) {
375+
die "Read an invalid UTF-8 string...";
376+
}
377+
```
378+
379+
The `utf8::valid()` function in PerlOnJava was using `CharsetDetector` which was fundamentally wrong:
380+
- It converted the string to bytes using the default charset
381+
- Then tried to detect if those bytes were UTF-8
382+
- This always failed for properly decoded Unicode strings
383+
384+
### Solution
385+
386+
Rewrote `utf8::valid()` in `Utf8.java` to correctly check string validity:
387+
- **For character strings (UTF-8 flag on)**: Validates that surrogate pairs are properly formed
388+
- **For byte strings (UTF-8 flag off)**: Attempts to decode bytes as UTF-8
389+
390+
### Files Changed
391+
392+
- `src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java` - Fixed `valid()` method
393+
394+
### Test Results
395+
396+
The fix allows CPAN::Meta::YAML to properly parse MYMETA.yml files, enabling CPAN.pm to detect and install test dependencies.
397+
398+
---
399+
400+
## Known Remaining CPAN Issues
401+
402+
| Issue | Status | Impact |
403+
|-------|--------|--------|
404+
| File::stat.pm missing | Not implemented | DateTime::Locale installation fails |
405+
| IPC::Open3 read-only error | Bug in IPCOpen3.java | Some module tests fail |
406+
| Test::Harness UTF-8 error | Pre-existing | Some test output parsing fails |
407+
408+
---
409+
358410
## Related Documents
359411

360412
- `dev/design/xsloader.md` - XSLoader/Java integration

dev/import-perl5/config.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ imports:
172172
- source: perl5/lib/File/Compare.pm
173173
target: src/main/perl/lib/File/Compare.pm
174174

175+
# File::stat - by-name interface to stat() (required by IO::Dir)
176+
- source: perl5/lib/File/stat.pm
177+
target: src/main/perl/lib/File/stat.pm
178+
175179
# From core library
176180
- source: perl5/lib/Tie/Array.pm
177181
target: src/main/perl/lib/Tie/Array.pm
@@ -620,6 +624,11 @@ imports:
620624
- source: perl5/cpan/Term-ANSIColor/lib/Term/ANSIColor.pm
621625
target: src/main/perl/lib/Term/ANSIColor.pm
622626

627+
# Class::Struct - Declare struct-like datatypes as Perl classes
628+
# Required by File::stat.pm
629+
- source: perl5/lib/Class/Struct.pm
630+
target: src/main/perl/lib/Class/Struct.pm
631+
623632
# Add more imports below as needed
624633
# Example with minimal fields:
625634
# - source: perl5/lib/SomeModule.pm

0 commit comments

Comments
 (0)