Check libraries for damage
PowerBuilder libraries get damaged, and the damage shows up late and far from its cause: an interrupted save, a copy over a network that failed halfway, two programs writing at once, a library optimised a thousand times over fifteen years. In one application, a DataWindow library carried damaged compiled objects for eleven builds in a row. The application crashed at run time, the IDE crashed opening those DataWindows, and the sources were intact all along. Checking the archived builds afterwards found exactly when it started and when the rebuilt library put it right; checking each build as it was made would have found it the same day.
validate checks libraries for that damage. It reads them
and never writes to them, so a damaged library is reported, not
repaired.
Check an application
Give validate the workspace, a target, the folder the
libraries are in, or the libraries themselves - as many as you like:
pb-diff-cli validate app.pbw
pb-diff-cli validate src\app.pbt deploy\
pb-diff-cli validate (Get-ChildItem src\*.pbl).FullName
A workspace stands for the libraries of its targets, and a target for
its library list, in search-path order; a PowerBuilder 2025 Solution and
its projects stand for the compiled libraries they list. A folder stands
for every .pbl and .pbd beneath it, which can
include old copies and other applications' libraries, so naming the
workspace or the target is usually what you want: it checks exactly the
libraries the application is built from, and says when one it names is
not there at all. When the workspace names a target that is gone, or a
list or folder cannot be read, that is said too, and the check does not
pass: libraries it stands for went unverified.
Each library gets one line, and its findings beneath it:
damaged src\orders.pbl 2 error(s), 0 warning(s) CHAIN_SHARED [d_order_lines.dwo]
error CHAIN_SHARED at 0x14000 [d_order_lines.dwo]: ...
valid src\customers.pbl
missing src\old_reports.pbl named by src\app.pbt
3 libraries: 1 valid, 1 damaged, 1 missing.
| State | Meaning |
|---|---|
| valid | Nothing worse than an observation was found. |
| warnings | Something is worth knowing, and nothing is damaged. |
| damaged | At least one error: the library is damaged. |
| unreadable | The file is there and cannot be read as a PowerBuilder library at all. |
| missing | A library list names it and it is not there. |
Check them on the desktop
Tools ▸ Verify Libraries opens a Library Verification tab. Give it what to check with Add Files - libraries, applications with a library appended, workspaces, targets, Solutions and projects - or Add Folder, or drop them on the tab. Verify in the File Selection's tool bar checks the libraries both of its lists stand for.
Each library appears as it is checked, with its state, its errors and warnings, and its worst finding; the status bar says how far the check has got, and Stop ends it after the library being read, keeping the ones already checked. Only problems hides the libraries that passed, and the notes above the grid say what could not be checked and why: a folder that could not be read, a target naming a library that is not there, a path that is not a library at all.
Select a library and its findings are listed beneath the grid, each
with the object it is about and where in the file it was found.
Open Library, Enter or a double-click opens
the library on a tab of its own, its findings beside its entries.
Save Report writes the result as Markdown, HTML or CSV,
as validate --output does.
Tools ▸ Validate Library checks the one library open on a tab; see Library.
Check a series of builds
When a library is damaged now, the archived builds say since when. Give the copies in the order they were built, and the results keep that order:
$builds = Get-ChildItem \\server\builds\*\arst_ppc.pbl | Sort-Object { $_.Directory.Name }
pb-diff-cli validate $builds --format json --out history.json
(Get-Content -Raw history.json | ConvertFrom-Json).libraries |
ForEach-Object { '{0,-10} {1}' -f $_.state, $_.container }
The first damaged copy is where the damage arrived, and the first valid one after it is where it was put right.
What it detects
It walks the structure the format document describes, and every finding has a stable code:
- The header and the blocks: the signatures that open the file, the directory and every data block, and offsets that point where a block can start.
- The directory: its nodes, their counts and bounds, entries in order, and no node reached twice.
- The entries: names and comments of the length they declare.
- The data chains: each entry's chain holding the
length the entry declares (
CHAIN_LENGTH), no chain running into itself (CHAIN_CYCLE) or into another entry's blocks (CHAIN_SHARED). - The free bitmap: every block in use marked as used
(
BITMAP_UNMARKED_BLOCK), and the count of blocks in use agreeing with what the directory reaches.
What it does not detect
It does not run, compile or decompile anything. A compiled object
whose structure is sound but whose P-code is wrong passes; a source that
does not compile passes - the compiler is what says that, and
check finds the sources a merge left broken. Of a file that
cannot be opened as a library, it says only why.
What to do about each finding
| Code | What it means | What to do |
|---|---|---|
CHAIN_SHARED |
Two objects' data run through the same block: at least one of them reads the other's bytes. | Rebuild the library: a full build from the sources, or a new library with the objects imported from source control. |
CHAIN_LENGTH |
An object declares more than its data holds: it is cut short. | Regenerate the object from its source, or rebuild the library. Never export it: the export would be short. |
CHAIN_CYCLE, CHAIN_READ,
CHAIN_BLOCK_LENGTH |
An object's data cannot be followed to its end. | As for CHAIN_LENGTH. |
BITMAP_UNMARKED_BLOCK |
Blocks in use are marked free: the next save may overwrite them. | Stop saving into the library, take a copy, and run an Optimize in the Library painter, which rewrites it; then check again. |
BITMAP_COUNT, BITMAP_BEYOND_EOF |
The bitmap's bookkeeping disagrees with the directory. | A warning: an Optimize rewrites the bitmap. |
BITMAP_UNMAINTAINED |
A compiled .pbd whose bitmap marks only an empty
library's blocks. |
Nothing: a build writes a .pbd whole, and Appeon's own
pb_sdk.pbd ships that way. |
| Any other error | The directory or the header is damaged. | Restore the library from a backup or source control, or rebuild it. |
A .pbd is the output of a build, so a damaged one is
rebuilt, not repaired. When the .pbl it was built from is
damaged too, rebuild that first.
In a pipeline
pb-diff-ci validate takes the same paths and gives the
same answers, with no licence and no network call. The worst library is
the exit code: 0 when every one is valid, 1 when the worst has warnings,
2 when any is damaged, unreadable or missing, or when a list or folder
could not be read. An input that stands for no library at all - an empty
folder, a mistyped path, a folder of sources - is refused rather than
passed.
.\tools\pb-diff-ci.exe validate src\app.pbw --output library-check.md
$code = $LASTEXITCODE
Get-Content library-check.md >> $env:GITHUB_STEP_SUMMARY
if ($code -ge 2) { throw 'A library is damaged, unreadable or missing.' }
--output also writes the result as Markdown, HTML or
CSV, chosen by the file name or by --report-format; Run pb-diff in CI shows where
each goes, and the Command-Line
Tool Reference describes every option.