A few weeks ago in When you get “TfsScript.Execute” throwing a “Unregistered version of FastScript.” I wrote about “a process that explains any modules in the MAP file not resulting in DCU files”.
The below batch file aids in that process.
It takes a MAP file from your Delphi compiled executable that has debug information in text format which means you need to set your project linker options to generate detailed MAP files.
The Map Debug File (*.map) – RAD Studio documentation hasn’t much information but points to Detailed-Segments Map File – RAD Studio which has a bit more. Neither contain information on Delphi units as they focus too much on the C++ side of things. Then there is a tiny bit information in Understanding Delphi MAP File – Stack Overflow.
So I did some spelunking and came up with this batch-file which will likely work back until about the Delphi 7 era:
@echo off if ["%*"]==[] goto :help :logic if not exist %1 goto :notExist setlocal :: do not use periods (.) in delims as unit names may contain them! :: it might be that the segment (%%a) for C=CODE/S=.text/G=(none)/M=*/ACBP=A9 is always 0001 :: it might be that the segment (%%a) for C=ICODE/S=.itext/G=(none)/M=*/ACBP=A9 is always 0002 :: it might be that the segment (%%a) for C=DATA/S=.data/G=DGROUP/M=*/ACBP=A9 is always 0003 :: it might be that the segment (%%a) for C=BSS/S=.bss/G=DGROUP/M=*/ACBP=A9 is always 0004 :: it might be that the segment (%%a) for C=TLS/S=.tls/G=(none)/M=*/ACBP=A9 is always 0005 :: the `if ["%%h"]==["(none)"] ` trick is to prevent this error: :: ) was unexpected at this time. for /f "tokens=1,2,3,4,5,6,7,8,9,10,11,12,13,14,* delims=()= " %%a IN (%1) do ( if [%%c]==[C] if [%%e]==[S] if [%%g]==[G] if [%%i]==[M] if [%%k]==[ACBP] if [%%l]==[A9] if [%%m]==[] ( if [%%d]==[CODE] if [%%f]==[.text] if ["%%h"]==["(none)"] echo %%j if [%%d]==[ICODE] if [%%f]==[.itext] if ["%%h"]==["(none)"] echo %%j if [%%d]==[DATA] if [%%f]==[.data] if ["%%h"]==["DGROUP"] echo %%j if [%%d]==[BSS] if [%%f]==[.bss] if ["%%h"]==["DGROUP"] echo %%j if [%%d]==[TLS] if [%%f]==[.tls] if ["%%h"]==["(none)"] echo %%j ) if [%%a]==[line] if [%%b]==[numbers] if [%%c]==[for] if [%%f]==[segment] if [%%g]==[.text] if [%%h]==[] ( echo %%d ) ) endlocal goto :eof echo a=%%a;b=%%b;b=%%b;c=%%c;d=%%d;e=%%e;f=%%f;g=%%g;h=%%h;i=%%i;j=%%j;k=%%k;l=%%l;m=%%m;n=%%n if [%%c]==[C] if [%%d]==[CODE] if [%%e]==[S] if [%%f]==[.text] if [%%g]==[G] if ["%%h"]==["(none)"] if [%%i]==[M] if [%%k]==[ACBP] if [%%l]==[A9] if [%%m]==[] echo %%j :notExist echo %* does not exist. :help echo syntax: %0 MAP-file echo will list all the Delphi units that got compiled into your EXE in a non-sorted non-unique way goto :eof
Pipe it through sort and then to some sort of uniq script like this PowerShell one.
Then check it against the sorted list of .DCU files the Delphi compiler produced for your project (ensure you cleaned the .DCU directory before compiling).
I usually use Beyond Compare to do this comparison for me.
–jeroen
Filed under: Delphi, Delphi 10 Seattle, Delphi 2005, Delphi 2006, Delphi 2007, Delphi 2009, Delphi 2010, Delphi 7, Delphi XE, Delphi XE2, Delphi XE3, Delphi XE4, Delphi XE5, Delphi XE6, Delphi XE7, Delphi XE8, Development, Software Development
