Pages

Wednesday, June 20, 2012

ClassDependsList - Building an ordered dependency list

In a previous post, the Topological Sort was mentioned. There is a well-written article here that explains the algorithm and how to implement it in C#. Let us use the same algorithm in our Java class example. The implementation will use bash and assume that the ClassDependsOn script is available in the PATH. After "visiting" a node in the graph, we use our previously-defined ClassDependsOn to find the neighbors.

Example

$ cd ~/Workspace/myswtproj

$ ClassDependsList MySwtProj.class >ClassDependsList.out

Expected Output (standard error)

Adding org/eclipse/swt/internal/SWTEventObject.class to list.
Adding org/eclipse/swt/internal/Library.class to list.
Adding org/eclipse/swt/internal/Lock.class to list.
Adding org/eclipse/swt/internal/Platform.class to list.
Adding org/eclipse/swt/internal/C.class to list.
Adding org/eclipse/swt/internal/Callback.class to list.
Adding org/eclipse/swt/internal/win32/ACCEL.class to list.
Adding org/eclipse/swt/internal/win32/ACTCTX.class to list.
Adding org/eclipse/swt/internal/win32/BITMAP.class to list.
Adding org/eclipse/swt/internal/win32/BITMAPINFOHEADER.class to list.
Adding org/eclipse/swt/internal/win32/BLENDFUNCTION.class to list.
Adding org/eclipse/swt/internal/win32/BP_PAINTPARAMS.class to list.
Adding org/eclipse/swt/internal/win32/BROWSEINFO.class to list.
Adding org/eclipse/swt/internal/win32/BUTTON_IMAGELIST.class to list.
Adding org/eclipse/swt/internal/win32/POINT.class to list.
Adding org/eclipse/swt/internal/win32/RECT.class to list.
Adding org/eclipse/swt/internal/win32/CANDIDATEFORM.class to list.
Adding org/eclipse/swt/internal/win32/CERT_CONTEXT.class to list.
Adding org/eclipse/swt/internal/win32/CERT_NAME_BLOB.class to list.
Adding org/eclipse/swt/internal/win32/CRYPT_OBJID_BLOB.class to list.
Adding org/eclipse/swt/internal/win32/CRYPT_ALGORITHM_IDENTIFIER.class to list.
Adding org/eclipse/swt/internal/win32/CRYPT_BIT_BLOB.class to list.
Adding org/eclipse/swt/internal/win32/CERT_PUBLIC_KEY_INFO.class to list.
Adding org/eclipse/swt/internal/win32/CRYPT_INTEGER_BLOB.class to list.
Adding org/eclipse/swt/internal/win32/FILETIME.class to list.
Adding org/eclipse/swt/internal/win32/CERT_INFO.class to list.
Adding org/eclipse/swt/internal/win32/CHOOSECOLOR.class to list.
Adding org/eclipse/swt/internal/win32/CHOOSEFONT.class to list.
Adding org/eclipse/swt/internal/win32/COMBOBOXINFO.class to list.
Adding org/eclipse/swt/internal/win32/COMPOSITIONFORM.class to list.
Adding org/eclipse/swt/internal/win32/CREATESTRUCT.class to list.
Adding org/eclipse/swt/internal/win32/DEVMODE.class to list.
Adding org/eclipse/swt/internal/win32/DEVMODEA.class to list.
Adding org/eclipse/swt/internal/win32/DEVMODEW.class to list.
Adding org/eclipse/swt/internal/win32/DIBSECTION.class to list.
Adding org/eclipse/swt/internal/win32/DLLVERSIONINFO.class to list.
Adding org/eclipse/swt/internal/win32/DOCHOSTUIINFO.class to list.
Adding org/eclipse/swt/internal/win32/DOCINFO.class to list.
Adding org/eclipse/swt/internal/win32/DRAWITEMSTRUCT.class to list.
Adding org/eclipse/swt/internal/win32/DROPFILES.class to list.
Adding org/eclipse/swt/internal/win32/DWM_BLURBEHIND.class to list.
Adding org/eclipse/swt/internal/win32/EMR.class to list.
Adding org/eclipse/swt/internal/win32/LOGFONTW.class to list.
Adding org/eclipse/swt/internal/win32/PANOSE.class to list.
Adding org/eclipse/swt/internal/win32/EXTLOGFONTW.class to list.
Adding org/eclipse/swt/internal/win32/EMREXTCREATEFONTINDIRECTW.class to list.
Adding org/eclipse/swt/internal/win32/EXTLOGPEN.class to list.
Adding org/eclipse/swt/internal/win32/FLICK_DATA.class to list.
Adding org/eclipse/swt/internal/win32/FLICK_POINT.class to list.
Adding org/eclipse/swt/internal/win32/GCP_RESULTS.class to list.
Adding org/eclipse/swt/internal/win32/GESTURECONFIG.class to list.
Adding org/eclipse/swt/internal/win32/GESTUREINFO.class to list.
Adding org/eclipse/swt/internal/win32/GRADIENT_RECT.class to list.
Adding org/eclipse/swt/internal/win32/GUITHREADINFO.class to list.
Adding org/eclipse/swt/internal/win32/HDHITTESTINFO.class to list.
Adding org/eclipse/swt/internal/win32/HDITEM.class to list.
Adding org/eclipse/swt/internal/win32/HDLAYOUT.class to list.
Adding org/eclipse/swt/internal/win32/HELPINFO.class to list.
Adding org/eclipse/swt/internal/win32/HIGHCONTRAST.class to list.
Adding org/eclipse/swt/internal/win32/ICONINFO.class to list.
Adding org/eclipse/swt/internal/win32/INITCOMMONCONTROLSEX.class to list.
Adding org/eclipse/swt/internal/win32/KEYBDINPUT.class to list.
Adding org/eclipse/swt/internal/win32/LITEM.class to list.
Adding org/eclipse/swt/internal/win32/LOGBRUSH.class to list.
Adding org/eclipse/swt/internal/win32/LOGFONTA.class to list.
Adding org/eclipse/swt/internal/win32/LOGPEN.class to list.
Adding org/eclipse/swt/internal/win32/LVCOLUMN.class to list.
Adding org/eclipse/swt/internal/win32/LVHITTESTINFO.class to list.
Adding org/eclipse/swt/internal/win32/LVINSERTMARK.class to list.
Adding org/eclipse/swt/internal/win32/LVITEM.class to list.
Adding org/eclipse/swt/internal/win32/MARGINS.class to list.
Adding org/eclipse/swt/internal/win32/SYSTEMTIME.class to list.
Adding org/eclipse/swt/internal/win32/MCHITTESTINFO.class to list.
Adding org/eclipse/swt/internal/win32/MEASUREITEMSTRUCT.class to list.
Adding org/eclipse/swt/internal/win32/MENUBARINFO.class to list.
Adding org/eclipse/swt/internal/win32/MENUINFO.class to list.
Adding org/eclipse/swt/internal/win32/MENUITEMINFO.class to list.
Adding org/eclipse/swt/internal/win32/MINMAXINFO.class to list.
Adding org/eclipse/swt/internal/win32/MONITORINFO.class to list.
Adding org/eclipse/swt/internal/win32/MOUSEINPUT.class to list.
Adding org/eclipse/swt/internal/win32/MSG.class to list.
Adding org/eclipse/swt/internal/win32/NMHDR.class to list.
Adding org/eclipse/swt/internal/win32/NMCUSTOMDRAW.class to list.
Adding org/eclipse/swt/internal/win32/NMHEADER.class to list.
Adding org/eclipse/swt/internal/win32/NMLINK.class to list.
Adding org/eclipse/swt/internal/win32/NMLISTVIEW.class to list.
Adding org/eclipse/swt/internal/win32/NMLVCUSTOMDRAW.class to list.
Adding org/eclipse/swt/internal/win32/NMLVDISPINFO.class to list.
Adding org/eclipse/swt/internal/win32/NMLVFINDITEM.class to list.
Adding org/eclipse/swt/internal/win32/NMLVODSTATECHANGE.class to list.
Adding org/eclipse/swt/internal/win32/NMREBARCHEVRON.class to list.
Adding org/eclipse/swt/internal/win32/NMREBARCHILDSIZE.class to list.
Adding org/eclipse/swt/internal/win32/NMRGINFO.class to list.
Adding org/eclipse/swt/internal/win32/NMTBHOTITEM.class to list.
Adding org/eclipse/swt/internal/win32/NMTOOLBAR.class to list.
Adding org/eclipse/swt/internal/win32/TVITEM.class to list.
Adding org/eclipse/swt/internal/win32/NMTREEVIEW.class to list.
Adding org/eclipse/swt/internal/win32/NMTTCUSTOMDRAW.class to list.
Adding org/eclipse/swt/internal/win32/NMTTDISPINFO.class to list.
Adding org/eclipse/swt/internal/win32/NMTTDISPINFOA.class to list.
Adding org/eclipse/swt/internal/win32/NMTTDISPINFOW.class to list.
Adding org/eclipse/swt/internal/win32/NMTVCUSTOMDRAW.class to list.
Adding org/eclipse/swt/internal/win32/NMTVDISPINFO.class to list.
Adding org/eclipse/swt/internal/win32/NMTVITEMCHANGE.class to list.
Adding org/eclipse/swt/internal/win32/NMUPDOWN.class to list.
Adding org/eclipse/swt/internal/win32/NONCLIENTMETRICS.class to list.
Adding org/eclipse/swt/internal/win32/NONCLIENTMETRICSA.class to list.
Adding org/eclipse/swt/internal/win32/NONCLIENTMETRICSW.class to list.
Adding org/eclipse/swt/internal/win32/NOTIFYICONDATA.class to list.
Adding org/eclipse/swt/internal/win32/NOTIFYICONDATAA.class to list.
Adding org/eclipse/swt/internal/win32/NOTIFYICONDATAW.class to list.
Adding org/eclipse/swt/internal/win32/OFNOTIFY.class to list.
Adding org/eclipse/swt/internal/win32/OPENFILENAME.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFO.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFOA.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFOEX.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFOEXA.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFOEXW.class to list.
Adding org/eclipse/swt/internal/win32/OSVERSIONINFOW.class to list.
Adding org/eclipse/swt/internal/win32/OUTLINETEXTMETRIC.class to list.
Adding org/eclipse/swt/internal/win32/TEXTMETRIC.class to list.
Adding org/eclipse/swt/internal/win32/TEXTMETRICA.class to list.
Adding org/eclipse/swt/internal/win32/OUTLINETEXTMETRICA.class to list.
Adding org/eclipse/swt/internal/win32/TEXTMETRICW.class to list.
Adding org/eclipse/swt/internal/win32/OUTLINETEXTMETRICW.class to list.
Adding org/eclipse/swt/internal/win32/PAINTSTRUCT.class to list.
Adding org/eclipse/swt/internal/win32/PRINTDLG.class to list.
Adding org/eclipse/swt/internal/win32/PROCESS_INFORMATION.class to list.
Adding org/eclipse/swt/internal/win32/PROPERTYKEY.class to list.
Adding org/eclipse/swt/internal/win32/REBARBANDINFO.class to list.
Adding org/eclipse/swt/internal/win32/SAFEARRAYBOUND.class to list.
Adding org/eclipse/swt/internal/win32/SAFEARRAY.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_STATE.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_ANALYSIS.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_CONTROL.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_DIGITSUBSTITUTE.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_FONTPROPERTIES.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_ITEM.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_LOGATTR.class to list.
Adding org/eclipse/swt/internal/win32/SCRIPT_PROPERTIES.class to list.
Adding org/eclipse/swt/internal/win32/SCROLLBARINFO.class to list.
Adding org/eclipse/swt/internal/win32/SCROLLINFO.class to list.
Adding org/eclipse/swt/internal/win32/SHACTIVATEINFO.class to list.
Adding org/eclipse/swt/internal/win32/SIZE.class to list.
Adding org/eclipse/swt/internal/win32/SHDRAGIMAGE.class to list.
Adding org/eclipse/swt/internal/win32/SHELLEXECUTEINFO.class to list.
Adding org/eclipse/swt/internal/win32/SHFILEINFO.class to list.
Adding org/eclipse/swt/internal/win32/SHFILEINFOA.class to list.
Adding org/eclipse/swt/internal/win32/SHFILEINFOW.class to list.
Adding org/eclipse/swt/internal/win32/SHMENUBARINFO.class to list.
Adding org/eclipse/swt/internal/win32/SHRGINFO.class to list.
Adding org/eclipse/swt/internal/win32/SIPINFO.class to list.
Adding org/eclipse/swt/internal/win32/STARTUPINFO.class to list.
Adding org/eclipse/swt/internal/win32/TBBUTTON.class to list.
Adding org/eclipse/swt/internal/win32/TBBUTTONINFO.class to list.
Adding org/eclipse/swt/internal/win32/TCHAR.class to list.
Adding org/eclipse/swt/internal/win32/TCHITTESTINFO.class to list.
Adding org/eclipse/swt/internal/win32/TCITEM.class to list.
Adding org/eclipse/swt/internal/win32/TF_DA_COLOR.class to list.
Adding org/eclipse/swt/internal/win32/TF_DISPLAYATTRIBUTE.class to list.
Adding org/eclipse/swt/internal/win32/TOOLINFO.class to list.
Adding org/eclipse/swt/internal/win32/TOUCHINPUT.class to list.
Adding org/eclipse/swt/internal/win32/TRACKMOUSEEVENT.class to list.
Adding org/eclipse/swt/internal/win32/TRIVERTEX.class to list.
Adding org/eclipse/swt/internal/win32/TVHITTESTINFO.class to list.
Adding org/eclipse/swt/internal/win32/TVINSERTSTRUCT.class to list.
Adding org/eclipse/swt/internal/win32/TVSORTCB.class to list.
Adding org/eclipse/swt/internal/win32/UDACCEL.class to list.
Adding org/eclipse/swt/internal/win32/WINDOWPLACEMENT.class to list.
Adding org/eclipse/swt/internal/win32/WINDOWPOS.class to list.
Adding org/eclipse/swt/internal/win32/WNDCLASS.class to list.
Adding org/eclipse/swt/internal/win32/OS.class to list.
Adding org/eclipse/swt/internal/win32/LOGFONT.class to list.
Adding org/eclipse/swt/internal/Compatibility.class to list.
Adding org/eclipse/swt/SWTError.class to list.
Adding org/eclipse/swt/SWTException.class to list.
Adding org/eclipse/swt/SWT.class to list.
Adding org/eclipse/swt/graphics/FontData.class to list.
Adding org/eclipse/swt/graphics/Resource.class to list.
Adding org/eclipse/swt/graphics/Font.class to list.
Adding org/eclipse/swt/internal/gdip/BitmapData.class to list.
Adding org/eclipse/swt/internal/gdip/ColorPalette.class to list.
Adding org/eclipse/swt/internal/gdip/GdiplusStartupInput.class to list.
Adding org/eclipse/swt/internal/gdip/PointF.class to list.
Adding org/eclipse/swt/internal/gdip/Rect.class to list.
Adding org/eclipse/swt/internal/gdip/RectF.class to list.
Adding org/eclipse/swt/internal/gdip/Gdip.class to list.
Adding org/eclipse/swt/graphics/Pattern.class to list.
Adding org/eclipse/swt/graphics/GCData.class to list.
Adding org/eclipse/swt/graphics/Drawable.class to list.
Adding org/eclipse/swt/graphics/FontMetrics.class to list.
Adding org/eclipse/swt/graphics/ImageLoaderEvent.class to list.
Adding org/eclipse/swt/internal/SWTEventListener.class to list.
Adding org/eclipse/swt/graphics/ImageLoaderListener.class to list.
Adding org/eclipse/swt/internal/image/LEDataInputStream.class to list.
Adding org/eclipse/swt/internal/image/LEDataOutputStream.class to list.
Adding org/eclipse/swt/internal/image/FileFormat.class to list.
Adding org/eclipse/swt/graphics/ImageLoader.class to list.
Adding org/eclipse/swt/graphics/ImageDataLoader.class to list.
Adding org/eclipse/swt/internal/SerializableCompatibility.class to list.
Adding org/eclipse/swt/graphics/RGB.class to list.
Adding org/eclipse/swt/graphics/PaletteData.class to list.
Adding org/eclipse/swt/internal/CloneableCompatibility.class to list.
Adding org/eclipse/swt/graphics/ImageData.class to list.
Adding org/eclipse/swt/graphics/LineAttributes.class to list.
Adding org/eclipse/swt/graphics/PathData.class to list.
Adding org/eclipse/swt/graphics/Path.class to list.
Adding org/eclipse/swt/graphics/Point.class to list.
Adding org/eclipse/swt/graphics/Rectangle.class to list.
Adding org/eclipse/swt/graphics/Region.class to list.
Adding org/eclipse/swt/graphics/Transform.class to list.
Adding org/eclipse/swt/graphics/GC.class to list.
Adding org/eclipse/swt/graphics/Image.class to list.
Adding org/eclipse/swt/graphics/Cursor.class to list.
Adding org/eclipse/swt/graphics/DeviceData.class to list.
Adding org/eclipse/swt/graphics/GlyphMetrics.class to list.
Adding org/eclipse/swt/graphics/TextStyle.class to list.
Adding org/eclipse/swt/graphics/TextLayout.class to list.
Adding org/eclipse/swt/graphics/Device.class to list.
Adding org/eclipse/swt/graphics/Color.class to list.
Adding org/eclipse/swt/internal/ImageList.class to list.
Adding org/eclipse/swt/internal/win32/INPUT.class to list.
Adding org/eclipse/swt/internal/win32/LRESULT.class to list.
Adding org/eclipse/swt/accessibility/AccessibleActionEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleActionListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleAdapter.class to list.
Adding org/eclipse/swt/accessibility/AccessibleAttributeEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTextAttributeEvent.class to list
Adding org/eclipse/swt/accessibility/AccessibleAttributeListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleControlEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleControlListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleEditableTextEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleEditableTextListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleHyperlinkEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleHyperlinkListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTableCellEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTableCellListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTableEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTableListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTextEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTextListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleTextExtendedListener.class to list.
Adding org/eclipse/swt/accessibility/AccessibleValueEvent.class to list.
Adding org/eclipse/swt/accessibility/AccessibleValueListener.class to list.
Adding org/eclipse/swt/internal/ole/win32/CAUUID.class to list.
Adding org/eclipse/swt/internal/ole/win32/CONTROLINFO.class to list.
Adding org/eclipse/swt/internal/ole/win32/DISPPARAMS.class to list.
Adding org/eclipse/swt/internal/ole/win32/DVTARGETDEVICE.class to list.
Adding org/eclipse/swt/internal/ole/win32/EXCEPINFO.class to list.
Adding org/eclipse/swt/internal/ole/win32/FORMATETC.class to list.
Adding org/eclipse/swt/internal/ole/win32/FUNCDESC.class to list.
Adding org/eclipse/swt/internal/ole/win32/GUID.class to list.
Adding org/eclipse/swt/internal/ole/win32/LICINFO.class to list.
Adding org/eclipse/swt/internal/ole/win32/OLECMD.class to list.
Adding org/eclipse/swt/internal/ole/win32/OLECMDTEXT.class to list.
Adding org/eclipse/swt/internal/ole/win32/OLEINPLACEFRAMEINFO.class to list.
Adding org/eclipse/swt/internal/ole/win32/STATSTG.class to list.
Adding org/eclipse/swt/internal/ole/win32/STGMEDIUM.class to list.
Adding org/eclipse/swt/internal/ole/win32/TYPEATTR.class to list.
Adding org/eclipse/swt/internal/ole/win32/VARDESC.class to list.
Adding org/eclipse/swt/internal/ole/win32/VARIANT.class to list.
Adding org/eclipse/swt/internal/ole/win32/COM.class to list.
Adding org/eclipse/swt/internal/LONG.class to list.
Adding org/eclipse/swt/internal/ole/win32/COMObject.class to list.
Adding org/eclipse/swt/accessibility/Relation.class to list.
Adding org/eclipse/swt/internal/ole/win32/IUnknown.class to list.
Adding org/eclipse/swt/internal/ole/win32/IDispatch.class to list.
Adding org/eclipse/swt/internal/ole/win32/IAccessible.class to list.
Adding org/eclipse/swt/internal/ole/win32/IEnum.class to list.
Adding org/eclipse/swt/internal/ole/win32/IEnumVARIANT.class to list.
Adding org/eclipse/swt/internal/ole/win32/IServiceProvider.class to list.
Adding org/eclipse/swt/ole/win32/OLE.class to list.
Adding org/eclipse/swt/widgets/TouchSource.class to list.
Adding org/eclipse/swt/widgets/Touch.class to list.
Adding org/eclipse/swt/events/DisposeEvent.class to list.
Adding org/eclipse/swt/events/DisposeListener.class to list.
Adding org/eclipse/swt/widgets/Listener.class to list.
Adding org/eclipse/swt/events/ArmEvent.class to list.
Adding org/eclipse/swt/events/ArmListener.class to list.
Adding org/eclipse/swt/events/ControlEvent.class to list.
Adding org/eclipse/swt/events/ControlListener.class to list.
Adding org/eclipse/swt/events/MouseEvent.class to list.
Adding org/eclipse/swt/events/DragDetectEvent.class to list.
Adding org/eclipse/swt/events/DragDetectListener.class to list.
Adding org/eclipse/swt/events/ExpandEvent.class to list.
Adding org/eclipse/swt/events/ExpandListener.class to list.
Adding org/eclipse/swt/events/FocusEvent.class to list.
Adding org/eclipse/swt/events/FocusListener.class to list.
Adding org/eclipse/swt/events/GestureEvent.class to list.
Adding org/eclipse/swt/events/GestureListener.class to list.
Adding org/eclipse/swt/events/HelpEvent.class to list.
Adding org/eclipse/swt/events/HelpListener.class to list.
Adding org/eclipse/swt/events/KeyEvent.class to list.
Adding org/eclipse/swt/events/KeyListener.class to list.
Adding org/eclipse/swt/events/MenuDetectEvent.class to list.
Adding org/eclipse/swt/events/MenuDetectListener.class to list.
Adding org/eclipse/swt/events/MenuEvent.class to list.
Adding org/eclipse/swt/events/MenuListener.class to list.
Adding org/eclipse/swt/events/ModifyEvent.class to list.
Adding org/eclipse/swt/events/ModifyListener.class to list.
Adding org/eclipse/swt/events/MouseListener.class to list.
Adding org/eclipse/swt/events/MouseMoveListener.class to list.
Adding org/eclipse/swt/events/MouseTrackListener.class to list.
Adding org/eclipse/swt/events/MouseWheelListener.class to list.
Adding org/eclipse/swt/events/PaintEvent.class to list.
Adding org/eclipse/swt/events/PaintListener.class to list.
Adding org/eclipse/swt/events/ShellEvent.class to list.
Adding org/eclipse/swt/events/ShellListener.class to list.
Adding org/eclipse/swt/events/TouchEvent.class to list.
Adding org/eclipse/swt/events/TouchListener.class to list.
Adding org/eclipse/swt/events/TraverseEvent.class to list.
Adding org/eclipse/swt/events/TraverseListener.class to list.
Adding org/eclipse/swt/events/TreeEvent.class to list.
Adding org/eclipse/swt/events/TreeListener.class to list.
Adding org/eclipse/swt/events/VerifyEvent.class to list.
Adding org/eclipse/swt/events/VerifyListener.class to list.
Adding org/eclipse/swt/widgets/TypedListener.class to list.
Adding org/eclipse/swt/widgets/EventTable.class to list.
Adding org/eclipse/swt/widgets/IME.class to list.
Adding org/eclipse/swt/widgets/Caret.class to list.
Adding org/eclipse/swt/widgets/Canvas.class to list.
Adding org/eclipse/swt/widgets/Layout.class to list.
Adding org/eclipse/swt/widgets/Item.class to list.
Adding org/eclipse/swt/widgets/MenuItem.class to list.
Adding org/eclipse/swt/widgets/Scrollable.class to list.
Adding org/eclipse/swt/widgets/ScrollBar.class to list.
Adding org/eclipse/swt/widgets/Dialog.class to list.
Adding org/eclipse/swt/widgets/Monitor.class to list.
Adding org/eclipse/swt/widgets/ToolItem.class to list.
Adding org/eclipse/swt/widgets/ToolBar.class to list.
Adding org/eclipse/swt/widgets/Tray.class to list.
Adding org/eclipse/swt/widgets/TrayItem.class to list.
Adding org/eclipse/swt/widgets/ToolTip.class to list.
Adding org/eclipse/swt/widgets/Shell.class to list.
Adding org/eclipse/swt/widgets/Decorations.class to list.
Adding org/eclipse/swt/widgets/Menu.class to list.
Adding org/eclipse/swt/widgets/Widget.class to list.
Adding org/eclipse/swt/widgets/Event.class to list.
Adding org/eclipse/swt/widgets/TabItem.class to list.
Adding org/eclipse/swt/widgets/TabFolder.class to list.
Adding org/eclipse/swt/widgets/TableItem.class to list.
Adding org/eclipse/swt/widgets/TableColumn.class to list.
Adding org/eclipse/swt/widgets/Table.class to list.
Adding org/eclipse/swt/widgets/TreeItem.class to list.
Adding org/eclipse/swt/widgets/TreeColumn.class to list.
Adding org/eclipse/swt/widgets/Tree.class to list.
Adding org/eclipse/swt/accessibility/Accessible.class to list.
Adding org/eclipse/swt/widgets/Control.class to list.
Adding org/eclipse/swt/widgets/Composite.class to list.
Adding org/eclipse/swt/widgets/RunnableLock.class to list.
Adding org/eclipse/swt/widgets/Synchronizer.class to list.
Adding org/eclipse/swt/widgets/TaskItem.class to list.
Adding org/eclipse/swt/widgets/TaskBar.class to list.
Adding org/eclipse/swt/widgets/Display.class to list.
Adding org/eclipse/swt/events/TypedEvent.class to list.
Adding org/eclipse/swt/events/SelectionEvent.class to list.
Adding org/eclipse/swt/events/SelectionListener.class to list.
Adding org/eclipse/swt/widgets/Button.class to list.
Adding org/eclipse/swt/widgets/DateTime.class to list.
Adding org/eclipse/swt/widgets/Label.class to list.
Adding MySWTTest.class to list.

File Output (ClassDependsList.out)

This file holds an ordered-list of classes, ending with MySwtProj.class.

The Code

#!/bin/bash
# Begin ClassDependsList
# Syntax: ClassDependsList CLASSNAME.class

TRUE=0
FALSE=1
declare -A node_mark_list

function node_mark
{

   local node="$1"
   node=${node//./0} # Replace all '.' with '0'
   node=${node//\//0} # Replace all '/' with '0'
   node=${node//\$/0} # Replace all ' with '0'
   node_mark_list[$node]="1"
}

function node_is_visited
{
   local node="$1"
   node=${node//./0} # Replace all '.' with '0'
   node=${node//\//0} # Replace all '/' with '0'
   node=${node//\$/0} # Replace all ' with '0'
   if [ "${node_mark_list[$node]}" == "1" ]; then
      return $TRUE
   fi
   return $FALSE
}
 

function visit
{
   local node="$1"
   local child

   # Stop traversal if node has already been visited,
   # otherwise mark the node as visited and continue
   if node_is_visited $node; then
      return
   else
      node_mark $node
   fi

   # For each child of node, visit it
   for child in `ClassDependsOn $node`
   do
      visit $child
   done

   # Add node to list
   list="${list}${node} "
   echo "Adding $node to list." >&2
}

classname="$1"
classname="${classname#.\/}" # Remove "./" from begin of classname if it is there

# For more convenient operation, change the CLASSPREFIX to an absolute path
# which is your base package directory
CLASSPREFIX="."

# Output list
list=""

visit $classname
echo "$list"

DONE

Wednesday, June 13, 2012

ClassDependsOn - Determining the dependency list for a class

Introduction

As discussed in the previous post, Compiling SWT Applications with GCJ, Part 2, we need a way to determine the dependencies of a class file in our topological sort. The tool I mentioned is called ClassDependsOn, and a simple implementation in bash is provided below.

Requirements / Assumptions

  • The ClassDependsOn script requires a Unix environment.
  • The tool jcf-dump  from the gcc-java package is required.
  • Recommended is to use Cygwin and install the gcc-java package with its installer.

Usage

  1. Place the ClassDependsOn script in your PATH and then cd into your base package directory. In our example, we are working with org.eclipse.swt, so our base package directory should contain the single folder org.
  2. Run ClassDependsOn and give as the argument a relative filename to the class without the .class extension.

Example and Expected Output


$ cd /cygdrive/c/MyBasePackageDirectory
$ ClassDependsOn org/eclipse/swt/browser/WebKit

org/eclipse/swt/browser/Browser.class
org/eclipse/swt/browser/BrowserFunction.class
org/eclipse/swt/browser/WebBrowser.class
org/eclipse/swt/browser/WebDownloadDelegate.class
org/eclipse/swt/browser/WebFrameLoadDelegate.class
org/eclipse/swt/browser/WebPolicyDelegate.class
org/eclipse/swt/browser/WebResourceLoadDelegate.class
org/eclipse/swt/browser/WebUIDelegate.class
org/eclipse/swt/graphics/Point.class
org/eclipse/swt/graphics/Rectangle.class
org/eclipse/swt/internal/C.class
org/eclipse/swt/internal/Callback.class
org/eclipse/swt/internal/Library.class
org/eclipse/swt/internal/ole/win32/COM.class
org/eclipse/swt/internal/ole/win32/GUID.class
org/eclipse/swt/internal/webkit/IWebCookieManager.class
org/eclipse/swt/internal/webkit/IWebDataSource.class
org/eclipse/swt/internal/webkit/IWebDocumentRepresentation.class
org/eclipse/swt/internal/webkit/IWebFrame.class
org/eclipse/swt/internal/webkit/IWebIBActions.class
org/eclipse/swt/internal/webkit/IWebMutableURLRequest.class
org/eclipse/swt/internal/webkit/IWebPreferences.class
org/eclipse/swt/internal/webkit/IWebView.class
org/eclipse/swt/internal/webkit/IWebViewPrivate.class
org/eclipse/swt/internal/webkit/JSClassDefinition.class
org/eclipse/swt/internal/webkit/WebKit_win32.class
org/eclipse/swt/internal/win32/OS.class
org/eclipse/swt/internal/win32/RECT.class
org/eclipse/swt/internal/win32/TCHAR.class
org/eclipse/swt/SWT.class
org/eclipse/swt/SWTError.class
org/eclipse/swt/SWTException.class
org/eclipse/swt/widgets/Composite.class
org/eclipse/swt/widgets/Control.class
org/eclipse/swt/widgets/Display.class
org/eclipse/swt/widgets/Event.class
org/eclipse/swt/widgets/Listener.class
org/eclipse/swt/widgets/Widget.class

The Code


#!/bin/bash
# Begin ClassDependsOn

# Syntax: ClassDependsOn CLASSNAME
# Reads a .class file determined by CLASSNAME and prints which packages it depends on
classname="$1"
classfiles="${classname}.class"

# For more convenient operation, change the CLASSPREFIX to an absolute path
# which is your base package directory
CLASSPREFIX="." 

# All files that have the class name or that have a $ afterwards are included in processing
for f in "${classname}"\$*
do
    if [ -e "$f" ]
    then
        classfiles="${classfiles} ${f}"
    fi
done

# Run 'jcf-dump -c' to get the information. Any strings that look like Java packages are taken.
# Assumes none of the class filenames have blanks in them (this is not allowed in Java classnames)
# Exclude 'This class' line in the output
deps="$(jcf-dump -c $classfiles | grep -Po '(\w+\.)+\w+' | sort | uniq)"

# Check each dependency and see if it is a class file
echo "$deps" | while read
do   
    package="$REPLY"
    package="${package//.//}"  # Replace all instances of '.' with '/'
   
    # If package is equivalent to the one we are looking for, exclude it
    if [ "$package" == "$classname" ]
    then
        continue   
    fi
   
    # If class file exists, output it
    if [ -e "${CLASSPREFIX}/${package}.class" ]
    then
        echo ${package}.class
    fi
done

Wednesday, May 30, 2012

Compiling SWT Applications with GCJ, Part 2

In the previous part, I compiled a simple SWT application using GCJ, but the size of the resulting EXE file was less than optimal:

27.724.288 Bytes

This is the result of linking with the very large swt.o - which was generated from swt.jar. A simple way to verify that we can do better: I will remove one of the .class files from swt.jar, and then try to recompile the test application SWTTest.

Here are the steps to follow:
  1. Extract the JAR contents.
  2. Remove a .class file that is not needed.
  3. Recreate the JAR.
  4. Rebuild the application.

For a simple experiment I decided to try and remove the Browser class. Afterwards, the resulting application size was reduced to 25.269.248 Bytes. So it already makes a bit of a difference just from removing this one unneeded class. But how can I optimally remove all unneeded classes?

Let me use a really naive procedure to try and optimize this. The SWT library can be thought of as a list of classes which we can number C_1, C_2, ..., C_N. I will arbitrarily choose a class C_x and remove it. Then, I will try to rebuild swt.o (this time without C_x) and finally to link it with the test application SWTTest. If the build/link succeeds, then the class C_x is evidently not needed for SWTTest.

However, a failure to build swt.o in this scenario does not necessarily mean that SWTTest needs the class C_x. For example, it could be the case that a different class in swt.jar is dependent on C_x (which we tried to remove) even though SWTTest does not need it. In fact, if we could find all of C_x's dependencies first and remove them, then the build of swt.o and subsequently of SWTTest would succeed.

One way to solve this problem is to sort the list of classes in order of increasing dependency, such that the least dependent classes come early and the most dependent packages come later. We can refer to this ordering informally as "build ordering" to build a project, the compiler must presumably build the classes in this order. Note that there may be more than one valid build ordering.

The procedure to produce this type of ordering is known as Topological Sort, which is described well in this article: patrick dewane gathers wool: Linear Ordering of Dependencies with a Topological Sort. After performing the topological sort, the classes are in our required build ordering.

Let me now define my naive algorithm more precisely:
Given as input: a list of classes and a project which depends on one or more classes in this list.
To be determined: the minimum list of required classes to build the project successfully.
  1. Sort all classes using the topological sort, such that the classes form a "build ordering". That is, if class B is dependent on class A, then class A must appear before class B in the sorted list. Let us refer to this sorted list of classes as L.
  2. Let i be an iterator for L = L[1], L[2], .... L[L.length]. Initially, i points to the last class in L. That is, i = L.length.
  3. Consider the class C = L[i]. Remove C from the JAR file and try to build the project. If the build fails, restore the removed class C to the JAR file. If the build succeeds, let L[i] = NULL.
  4. Let i = i - 1 and repeat step 3. Stop when i = 0 (no more classes are left).
  5. Remove all NULL entries from list L to produce list LStar. The list LStar[1], LStar[2], ..., LStar[LStar.length] is the minimum list of required classes.
Notes:
  • The inputs for our test case are: the list of classes in org.eclipse.swt, and the project SWTTest (a simple "Hello World" project that uses SWT).
  • For Step 1 (Topological sort): To simplify checking the dependency of each class, let us assume a tool exists called ClassDependsOn which returns the dependency list of a given .class file.
  • For Step 3 (Removing a class): When removing a class called SomeClass, there may be multiple files associated with this class named SomeClass.class, SomeClass$1.class, SomeClass$2.class, .... When removing SomeClass, it is necessary to remove all of these files.
  • For Step 3 (Restoring a class): To facilitate easily restoring a removed class, do not actually delete .class files when removing the class. Instead, move them outside of the JAR file. A simple way to do this is as follows: Suppose you are building the JAR files from inside the directory called C:\Foo. In this case, removing the class SomeClass means to move the file SomeClass.class which is located in the directory C:\Foo\com\mycompany\mypackage into a directory called C:\Foo.trash\com\mycompany\mypackage. Notice that the trash folder C:\Foo.trash should have an identical folder structure as C:\Foo.
  • For Step 3 (Testing the build): To test the build, it seems it is necessary to make a JAR file first and then build the JAR, resulting in swt.o. Afterwards compile and link the SWTTest project as described in Compiling SWT Applications with GCJ, Part 1 to verify the build process.

Compiling SWT Applications with GCJ, Part 1

Using GCJ to compile a native Windows app using SWT. Can it be done?

The GCJ compiler from GNU's Compiler Collection generates native code from either the .java source files of a project or from the precompiled .class bytecode that has been generated from another compiler like Sun's (Oracle's) javac.

But it seems this piece of the GCC has not been maintained as well as the others. The MinGW project which releases binaries for gcc meant for use with Windows states the following on their most download page for gcc (version 4.6.2):

* The Java language is absent, pending resolution of build issues. The last mingw.org release offering Java was 4.4.0.

http://sourceforge.net/projects/mingw/files/MinGW/Base/gcc/Version4/gcc-4.6.2-1/
Okay, great... build issues. Well, if the MinGW people can't build it on Windows, I probably won't have much better luck. I'm currently using the binary offered by the thisiscool.com page on GCC MinGW.

I am using the archive with the filename gcc43ecj-20061207.tar.bz2. gcc reports
Thread model: win32
gcc version 4.3.0 20061108 (gcj-eclipse experimental)
Ok, so let's use it. I installed into C:\thisiscool-gcc and then extended my PATH to include the bin directory:
SET PATH=c:\thisiscool-gcc\gcc-ecj\bin;%PATH%
Now, let's move into the directory with my SWT distribution, org.eclipse.swt and try to compile it. I'm using the source available at the Eclipse Download Page for SWT. There you will find several links to download.

Thanks to the notes from this blog comment from Radu Racariu, I was able to get this to work. To compile a SWT program, you first compile the entire swt.jar into an .o file. Here is the result:

Image 1: Result of compiling swt.jar using the command gcj -c -fjni -g0 swt.jar
Wait a minute. The resulting file swt.o is over 20MB! How can I make it smaller? Well, I tried several things, but none of them worked:
  • Compiling with gcj -Os seems to cause my poor laptop to slowly die. After about 3 hours, gcj is hogging 600 MB of RAM and no sign that it will finish. Eventually it dies with a message about unable to allocate more memory.
  • In theory one can extract the JAR contents and compile each .class file separately. However, when it comes to linking (next step, below) I could not get the resulting program to work.
  • According to the GNU people, even better than compiling .class files is to compile the .java files. But this does not succeed. I might have something misconfigured, or there might be some incompatibilities in the Java language variant used to develop SWT.
Ok... so I will stick with this solution. But, how is the resulting executable? I compile a simple SWT test program with gcj like this:
set CLASSPATH=..\..\org.eclipse.swt\swt.jar
gcj -o MySWTTest.exe -s --main=MySWTTest MySWTTest.class ..\..\org.eclipse.swt\swt.o
It works, but the resulting .exe is over 27 megabytes in size... All it does is display a message, a button and a DateTime selector:

Image 2: Simple SWT Test program running to show that the GCJ-generated SWT app actually works
Ok... so it is possible to compile SWT programs into native Windows binaries, but how can we reduce the filesize? I try to tackle this problem in my next post.