Application packaging hints
The packaging process is guided by a set of rules based on a packaging instruction. The packaging instruction is in the form of a Smalltalk class; the packager interacts with the instruction by sending messages to determine the exact contents of the packaged image. You interact with the packaging instruction through the Packager Control Panel.
Instantiations provides a number of packaging instructions to assist you in building a packaged application image.
The following list details methods that you can include in your application to make it more "packager friendly". Note that these methods should be defined as class methods in your application class.
This method answers a SequenceableCollection of symbols that represents method selectors within the application that should always be included when the application is packaged. The packager uses this method to determine the list of selectors that the application should always include even if there is no explicit reference to them in the code being packaged
This method should return a list of method names that are not directly referenced by your application, but which you want to include in the packaged image. You might use this method if your code uses perform: to send messages at runtime. For example, suppose a class implements seven methods, one for each day of the week, and you call these methods based on the following code:
dayMethod := Date today asLowercase asSymbol.
self perform: dayMethod.
Then, the seven methods are not directly referenced and the packager will assume that they are not needed in the packaged image. To include them, implement the following class method in the application class:
"Return a list of method selectors that must be
included in the packaged image."
^ #(monday tuesday wednesday thursday friday saturday sunday)
The packager assumes that any symbols it finds in the source code of applications are references to methods. The packager does this to minimize problems caused by the use of perform:, as noted above. When the packager looks for errors, it may produce a list of warnings related to symbols that are used only to describe state and are not used as selectors.
To eliminate these errors, your application can return a list of known symbols. The application should provide a class method named packagerKnownSymbols that returns a list of these symbols. This method answers an array of symbols used as atoms within the application. This instructs the packager to filter these symbols from any check done to verify that each known symbol has at least one implementor.
You can use atoms instead of symbols for the purpose of identifying state. For example, use ##mode instead of #mode. Atoms are instances of EsAtom. The packager does not interpret atoms as selectors, so the use of atoms reduces the need for packagerKnownSymbols
Sometimes no direct references to classes in your application code exist in the packaged image. This situation can occur when, for example, you read data from an external file and convert it into objects within the image.
For example, suppose you want to create, from an ASCII file, EmployeeRecord (an abstract class) that may be SalariedEmployeeRecord or WeeklyEmployeeRecord (concrete subclasses). You can read an identifier from the file and then broadcast a message to subclasses of the abstract class to determine which kind of object is in the file at this point. For example:
EmployeeRecord allSubclasses detect: [ :class |
class forIdentifier: identifierJustRead ].
The class thus identified (which has to know by which identifier it is described) then reads the rest of its information from the stream.
Because a message was broadcast to subclasses, there is no direct reference to the subclasses. If there is no other reference to these classes, the packager will omit them and the application will fail.
If your application uses this technique or a similar one, it should implement a class method named packagerIncludeClassNames, which returns a list of classes to include in the packaged image. In the above example, the method may look like the following:
"Return a list of class names that must be included
in the packaged image."
^ EmployeeRecord allSubclasses collect: [ :each | each symbol ].
If you are packaging in XD, the example code above will not work because it requires executing Smalltalk code to answer a result. Instead you will need to code the method like this so that it answers a static value:
"Return a list of class names that must be included
in the packaged image."
^ #(
Here is the code used to build the method content above:
| ans |
ans := EmployeeRecord allSubclasses collect:[ : each | each symbol ].
Transcript cr; tab; nextPutAll: '#('.
ans asSortedCollection do:[ : sym | Transcript cr; tab; tab; nextPutAll: sym ].
Transcript cr; tab; nextPut: $)
Sometimes a class may override the doesNotUnderstand: method and then redispatch a different method. For example, you might have a set of selectors (#sequentialFile, #keyedFile, and #directFile) that are sent to some central point, trapped through doesNotUnderstand:, then redispatched as #sequentialFileFor:, #keyedFileFor:, and #directFileFor: to an appropriate service by code such as the following:
doesNotUnderstand: aMessage
"Forward the given request to the appropriate service."
| oldSelector newSelector service |
oldSelector := aMessage selector.
newSelector := (oldSelector, 'For:') asSymbol.
service := self serviceAppropriateFor: oldSelector.
^ service perform: newSelector with: self
If your application uses this coding style, you should define the method packagerTranslateSelectors in your application class. This method should return a dictionary with the keys being the original selectors and the values being the redispatched selectors. The packager will then include in the packaged image methods referenced by both the key and value of each entry. In the above example, the method would look like this:
"Return a dictionary of translated selectors."
^ Dictionary new
at: #sequentialFile put: #sequentialFileFor:;
at: #keyedFile put: #keyedFileFor:;
at: #directFile put: #directFileFor:;
This method allows an application to provide a list of selectors to which references can be ignored. This method is functionally identical to packagerKnownSymbols, however, methods identified with packagerIgnoreSelectors are not made visible to the user.
This method returns a list of selectors. The packager will ignore any invalid references inside of the methods represented by this list.
Last modified date: 05/19/2020