One thing that we get a number of questions on is "how do I build an exe"? It's a question newcomers to VW ask - partly because building a simple "Hello World" application is so easy in tools like VS (although, to be fair, things get complex quickly with the various makifile options in a complex app). The thing that tends to initially stop neophytes in VW is that the process starts out harder than it does for other tools. It has a fairly consistent level of complexity though, so over time, it doesn't tend to get worse. Having said that, let me walk through what I do for BottomFeeder. There are steps here that not everyone will need, but the outline should be useful. All of the code below runs from a workspace, btw:
"load all my needed parcels (Windows)"
#(
'$(VISUALWORKS)\image\Pollock.pcl'
'$(VISUALWORKS)\parcels\ce.pcl'
'$(VISUALWORKS)\preview\Unicode\AllEncodings.pcl'
'$(VISUALWORKS)\preview\Unicode\UnicodeCharacterInput.pcl'
'$(VISUALWORKS)\dllcc\dllcc.pcl'
'$(VISUALWORKS)\security\des.pcl'
'$(VISUALWORKS)\net\netclients.pcl'
'$(VISUALWORKS)\parcels\XSL.pcl'
'$(VISUALWORKS)\opentalk\Opentalk-STST.pcl'
'$(VISUALWORKS)\webservices\UDDIInquire.pcl'
'$(VISUALWORKS)\image\rss\WindowsGoodies.pcl'
'$(VISUALWORKS)\parcels\MacExtra.pcl'
'$(VISUALWORKS)\parcels\PNGImageReader.pcl'
'$(VISUALWORKS)\packaging\RuntimePackager.pcl'
'$(VISUALWORKS)\image\rss\ImageConfig.pcl'
'$(VISUALWORKS)\image\rss\MouseWheelX11.pcl'
'$(VISUALWORKS)\goodies\parc\VRGoodies\VRFileReading.pcl'
'$(VISUALWORKS)\image\rss\StartupTools.pcl'
'$(VISUALWORKS)\image\dev\SpellChecker.pcl'
'$(VISUALWORKS)\image\dev\WinGDIPlusInterface.pcl'
'$(VISUALWORKS)\image\dev\EpiWin32Folder.pcl'
'$(VISUALWORKS)\image\dev\GIFSupport.pcl'
'$(VISUALWORKS)\image\dev\Weaklings.pcl'
'$(VISUALWORKS)\image\dev\Emote-Support.pcl'
'$(VISUALWORKS)\image\dev\ExtraEmphases.pcl'
'$(VISUALWORKS)\image\dev\ExtraActivity.pcl'
'$(VISUALWORKS)\image\dev\VRCommonDialogs.pcl'
'$(VISUALWORKS)\image\dev\XmlRpcClient.pcl'
'$(VISUALWORKS)\image\dev\Http-Overrides.pcl'
'$(VISUALWORKS)\image\dev\NetResources.pcl'
'$(VISUALWORKS)\image\dev\NetResourcesHttp.pcl'
'$(VISUALWORKS)\image\dev\LibTidy.pcl'
'$(VISUALWORKS)\image\dev\Win32TaskbarSupport.pcl'
'$(VISUALWORKS)\image\dev\WindowsTrayIcons.pcl'
'$(VISUALWORKS)\image\dev\Browsing-Assist.pcl'
'$(VISUALWORKS)\image\dev\OSTimeZone.pcl'
'$(VISUALWORKS)\image\dev\XML-Configuration-Files.pcl'
'$(VISUALWORKS)\image\dev\PatchFileDelivery.pcl'
'$(VISUALWORKS)\image\dev\TwoFlower.pcl'
'$(VISUALWORKS)\image\WithStyle4-4.422\WithStyle.pcl'
'$(VISUALWORKS)\image\dev\WSBundle.pcl'
'$(VISUALWORKS)\image\dev\WSEdit.pcl'
'$(VISUALWORKS)\image\dev\BFSharedIcons.pcl'
'$(VISUALWORKS)\image\Blog-Tools.pcl'
'$(VISUALWORKS)\image\dev\BottomFeeder.pcl'
'$(VISUALWORKS)\image\IRC-BottomFeeder-Plugin.pcl'
'$(VISUALWORKS)\image\Pongo.pcl'
) do: [:each |
Parcel loadParcelFrom: each].
That initial step loads all of the code that makes up BottomFeeder - the pre-reqs and the aplication itself. Next, there are some "set up" steps that put release information in place:
"Register the Blog-Tools plugin"
#{RSS.RSSFeedViewer} ifDefinedDo: [:cls | cls
registerPluginClass: BlogTools.PostingTool
startupMessage: #openWith:
label: 'Bottom Line'].
"set version and release date info"
RSSPersistence.SystemStartup version: '3.9'.
RSSPersistence.SystemStartup releaseDate: (Date today printString).
RSSPersistence.SystemStartup logo: 'watermark.bmp'.
RSSPersistence.SystemStartup helpLogo: 'watermark.bmp'.
That first step registers a plugin (should happen on load, but there's a bit of stupidity in the way I've defined things. Anyway... The latter few steps simply define release information for the Help>>About dialog. Next, I set up message catalogs. This may well not be the ideal way to do this; you should check the docs:
"set up catalogs"
IndexedFileMessageCatalog closeCatalogs.
IndexedFileMessageCatalog.Catalogs := OrderedCollection new.
('catalog\en\bottomfeeder.lbl' asFilename exists)
ifTrue: ['catalog\en\bottomfeeder.lbl' asFilename delete].
('catalog\en\bottomfeeder.idx' asFilename exists)
ifTrue: ['catalog\en\bottomfeeder.idx' asFilename delete].
'swapcats\bottomfeeder.lbl' asFilename copyTo: 'catalog\en\bottomfeeder.lbl'.
"add directory to message catalogs list for lookup purposes"
mine := IndexedFileMessageCatalog directoriesModel value detect: [:each |
'catalog' = each asString] ifNone: [nil].
mine ifNil: [| file |
file := PortableFilename named: 'catalog'.
IndexedFileMessageCatalog directoriesModel value add: file].
"index the catalog"
IndexedFileMessageCatalog
compileAllCatalogsFor: 'catalog'.
"set the herald string"
ObjectMemory setHeraldString: 'BottomFeeder - Released on ', Date today printString.
That last step changes the herald string (in the splash screen) to something appropriate. I change the splash screen itself using ResHacker, which I'll get to below. Finally, I remove any undeclareds that are load artifacts, and then start RuntimePackager from the tools menu:
"remove WebSettings from deps - can interfere with cmd line reading"
ObjectMemory removeDependent: WebSettings.
Undeclared keys do: [:each |
Undeclared removeKey: each].
After that step, I close the workspace I was running those steps in, and use RTP. I've saved the settings for it, but I'll include a couple of screen shots. First, the screen that defines the startup:
This is where you specify which class makes up your application, and what method should be used to kick it off. In my case, that's not an "open" method - the startup sequence for Bf looks for updates and a number of other things. In general though, this is the crucial part of RTP. The next piece is something you should ignore on your first use - the scan for things to remove. Just let the app be "bloated" for now - you can worry about having it try and pull stuff later:
For now, it's best to just hit "Next" and skip this part. You'll end up with a larger runtime, but it won't fail for odd looking reasons. Finally, go to the end and have it run the packager. You'll end up with a runtime image (bottomFeeder.im based on the way I filled the first screen above out). Now, if you are on Windows, you can create an executable. Here's the steps I use for that (I loaded a goodie called WinProcess for this part. It's in goodies/other/heeg):
" get the executor "
executor := OSSystemSupport concreteClass.
"compress the image"
compressor := 'C:\vw73\packaging\win\imageCompress '.
input := ' bottomFeeder.im '.
output := ' bfeed.im '.
exe0 := compressor, input, output.
executor CreateProcess: nil arguments: exe0.
"prepare unified windows image"
resHacker := 'C:\vw73\packaging\win\ResHacker '.
image := 'bfeed.im'.
exe := 'bottomFeeder.exe'.
vm := 'C:\vw73\bin\win\visual.exe'.
ico := 'bfSplash.ico'.
bmp := 'bfSplash.bmp'.
exe1 := resHacker, ' -addoverwrite ', vm, ', ', exe, ', ', image, ', 332, 332,'.
exe2 := resHacker, ' -addoverwrite ', exe, ', ', exe, ', ', ico, ', icon, 323, 1'.
exe3 := resHacker, ' -addoverwrite ', exe, ', ', exe, ', ', bmp, ', bitmap, 324,'.
exe4 := resHacker, ' -addoverwrite ', exe, ', ', exe, ', devname.txt, 325, 325,'.
WinProcess cshOne: exe1.
WinProcess cshOne: exe2.
WinProcess cshOne: exe3.
WinProcess cshOne: exe4.
The first step compresses the image. The next few create the executable, using the options specified in the middle segment there (exe name, splash screen, etc). There's doc on this in $VISUALWORKS/packaging/win. At the end of all that, you'll have an executable. I go through an extra step, using NullSoft's installer package to create a nice Windows installer. That's outside the scope of this post though.
Questions? Contact me