#FEATURE by stefan
authorStefan Vogel <sv@exept.de>
Thu, 17 Oct 2019 14:36:55 +0200
changeset 4583 18c9ee9d89f4
parent 4582 120e83524d09
child 4584 e40bd4b82075
#FEATURE by stefan class: ObjectFileLoader class comment/format in: #loadObjectFile: changed: #loadObjectFile:invokeInitializeMethods: #unloadObjectFile: #unloadObjectFileAndRemoveClasses: If an Objectfile cannot be loaded due to PackageLoadError (e.g. missing license), remove ist from the system.
ObjectFileLoader.st
--- a/ObjectFileLoader.st	Sun Oct 13 23:31:57 2019 +0200
+++ b/ObjectFileLoader.st	Thu Oct 17 14:36:55 2019 +0200
@@ -1238,6 +1238,7 @@
         invokeInitializeMethods:true
 
     "Modified (comment): / 10-04-2019 / 05:47:49 / Claus Gittinger"
+    "Modified: / 17-10-2019 / 13:46:10 / Stefan Vogel"
 !
 
 loadObjectFile:pathNameOrFilename invokeInitializeMethods:invokeInitializeMethods
@@ -1257,13 +1258,13 @@
 
     handle := self handleForDynamicObject:filename.
     handle notNil ifTrue:[
-	"already loaded"
-	^ handle.
+        "already loaded"
+        ^ handle.
     ].
 
     handle := self loadDynamicObject:filename.
     handle isNil ifTrue:[
-	^ nil
+        ^ nil
     ].
 
     didInit := false.
@@ -1273,23 +1274,23 @@
      are to be resolved. If that's the case, load all libraries ..."
 
     ParserFlags searchedLibraries notEmptyOrNil ifTrue:[
-	(self hasUndefinedSymbolsIn:handle) ifTrue:[
-	    self initializeLoader.
-
-	    ParserFlags searchedLibraries do:[:libName |
-		(self hasUndefinedSymbolsIn:handle) ifTrue:[
-		    Logger info:'   ... trying  %1 to resolve undefined symbols ...' with:libName.
-		    dummyHandle := Array new:4.
-		    dummyHandle := self primLoadDynamicObject:libName into:dummyHandle.
+        (self hasUndefinedSymbolsIn:handle) ifTrue:[
+            self initializeLoader.
+
+            ParserFlags searchedLibraries do:[:libName |
+                (self hasUndefinedSymbolsIn:handle) ifTrue:[
+                    Logger info:'   ... trying  %1 to resolve undefined symbols ...' with:libName.
+                    dummyHandle := Array new:4.
+                    dummyHandle := self primLoadDynamicObject:libName into:dummyHandle.
 "/                    dummyHandle isNil ifTrue:[
 "/                        Transcript showCR:'   ... load of library ' , libName , ' failed.'.
 "/                    ]
-		]
-	    ].
-	    (self hasUndefinedSymbolsIn:handle) isNil ifTrue:[
-		Logger info:'still undefined symbols in %1.' with:pathName.
-	    ].
-	]
+                ]
+            ].
+            (self hasUndefinedSymbolsIn:handle) isNil ifTrue:[
+                Logger info:'still undefined symbols in %1.' with:pathName.
+            ].
+        ]
     ].
 
     "
@@ -1304,212 +1305,222 @@
      This is used in ST packaged classLib object files"
 
     (initFunctionName startsWith:'lib') ifTrue:[
-	definitionClassName := initFunctionName copyFrom:4.
-	definitionClass := Smalltalk classNamed:definitionClassName.
+        definitionClassName := initFunctionName copyFrom:4.
+        definitionClass := Smalltalk classNamed:definitionClassName.
     ].
-    (definitionClass isNil or:[definitionClass isLoaded not]) ifTrue:[
-	"the project definition class has not been loaded yet.
-	 initialize and load it"
-
-	initDefinitionAddr := self findInitDefinitionFunction:initFunctionName in:handle.
-	initDefinitionAddr isNil ifTrue:[
-	    ('ObjectFileLoader [warning]: no init definitions for: ' , pathName) infoPrintCR.
-	] ifFalse:[
-	    Verbose ifTrue:[
-		('ObjectFileLoader [info]: calling initDefinition at:' , (initDefinitionAddr printStringRadix:16)) infoPrintCR.
-	    ].
-	    info := self
-			performModuleInitAt:initDefinitionAddr
-			invokeInitializeMethods:false
-			for:definitionClassName
-			identifyAs:handle.
-	    status := info at:1.
-	    status == #ok ifTrue:[
-		"/ now, we have only loaded and installed the projectDefinition class.
-		"/ (but no containing classes or extensions, yet).
-		"/ let the projectDefinition load any prereqs
-	       definitionClassName notNil ifTrue:[
-		    definitionClass := Smalltalk classNamed:definitionClassName.
-		    definitionClass notNil ifTrue:[
-"/                        "if projectDefinition denies loading, unload"
-"/                            self unloadDynamicObject:handle.
-
-			definitionClass
-			    checkForLoad;                           "/ raise exception if not supported on platform / not licensed
-			    initialize;
-			    preLoadAction;
-			    loadMandatoryPreRequisitesAsAutoloaded:false.
-		    ].
-		].
-	    ]
-	].
+    (definitionClass isNil or:[definitionClass isLoaded not or:[definitionClass isObsolete]]) ifTrue:[
+        "the project definition class has not been loaded yet.
+         initialize and load it"
+
+        initDefinitionAddr := self findInitDefinitionFunction:initFunctionName in:handle.
+        initDefinitionAddr isNil ifTrue:[
+            ('ObjectFileLoader [warning]: no init definitions for: ' , pathName) infoPrintCR.
+        ] ifFalse:[
+            Verbose ifTrue:[
+                ('ObjectFileLoader [info]: calling initDefinition at:' , (initDefinitionAddr printStringRadix:16)) infoPrintCR.
+            ].
+            info := self
+                        performModuleInitAt:initDefinitionAddr
+                        invokeInitializeMethods:false
+                        for:definitionClassName
+                        identifyAs:handle.
+            status := info at:1.
+            status == #ok ifTrue:[
+                "/ now, we have only loaded and installed the projectDefinition class.
+                "/ (but no containing classes or extensions, yet).
+                "/ let the projectDefinition load any prereqs
+               definitionClassName notNil ifTrue:[
+                    definitionClass := Smalltalk classNamed:definitionClassName.
+                    definitionClass notNil ifTrue:[
+                        [                
+                            definitionClass checkForLoad.   "/ raise exception if not supported on platform / not licensed
+                        ] on:PackageLoadError do:[:ex|
+                            self unloadObjectFileAndRemoveClasses:pathName.
+                            ex reject.     
+                            ^ nil.
+                        ].
+                        definitionClass 
+                            initialize;
+                            preLoadAction;
+                            loadMandatoryPreRequisitesAsAutoloaded:false.
+                    ].
+                ].
+            ]
+        ].
     ].
     "look for explicit init (xxx_Init) function
      This is used in ST object files"
 
     initAddr := self findInitFunction:initFunctionName in:handle.
     initAddr notNil ifTrue:[
-	Verbose ifTrue:[
-	    ('ObjectFileLoader [info]: calling init at:' , (initAddr printStringRadix:16)) infoPrintCR.
-	].
-	info := self
-		    performModuleInitAt:initAddr
-		    invokeInitializeMethods:invokeInitializeMethods
-		    for:nil
-		    identifyAs:handle.
-	status := info at:1.
-	status == #ok ifTrue:[
-	    didInit := true.
-	    definitionClassName notNil ifTrue:[
-		definitionClass := Smalltalk classNamed:definitionClassName.
-	    ]
-	]
+        Verbose ifTrue:[
+            ('ObjectFileLoader [info]: calling init at:' , (initAddr printStringRadix:16)) infoPrintCR.
+        ].
+        info := self
+                    performModuleInitAt:initAddr
+                    invokeInitializeMethods:invokeInitializeMethods
+                    for:nil
+                    identifyAs:handle.
+        status := info at:1.
+        status == #ok ifTrue:[
+            didInit := true.
+            definitionClassName notNil ifTrue:[
+                definitionClass := Smalltalk classNamed:definitionClassName.
+            ]
+        ]
     ] ifFalse:[
-	"look for explicit C-init (xxx__Init) function
-	 This is used in C object files"
-
-	initAddr := self findFunction:initFunctionName suffix:'__Init' in:handle.
-	initAddr notNil ifTrue:[
-	    isCModule := true.
-
-	    OSSignalInterrupt handle:[:ex |
-		Logger error:'hard error in initFunction of class-module: %1' with:pathName.
-		status := #initFailed.
-	    ] do:[
-		cRetVal := self
-		    saveCallInitFunctionAt:initAddr
-		    in:pathNameOrFilename
-		    specialInit:false
-		    forceOld:true
-		    interruptable:false
-		    argument:0
-		    identifyAs:handle
-		    returnsObject:false.
-		(cRetVal < 0) ifTrue:[
-		    Verbose ifTrue:[
-			'ObjectFileLoader [warning]: init function returns failure ... unload' infoPrintCR.
-		    ].
-		    status := #initFailed.
-		] ifFalse:[
-		    didInit := true.
-		]
-	    ]
-	] ifFalse:[
-	    status := #noInitFunction.
-
-	    "look for any init-function(s); call them all"
-	    Verbose ifTrue:[
-		'ObjectFileLoader [info]: no good init functions found; looking for candidates ...' infoPrintCR.
-	    ].
-	    initNames := self namesMatching:'*_Init' segment:'[tT?]' in:pathName.
-	    initNames notNil ifTrue:[
-		initNames do:[:aName |
-		    initAddr := self getFunction:aName from:handle.
-		    initAddr isNil ifTrue:[
-			(aName startsWith:'_') ifTrue:[
-			    initAddr := self getFunction:(aName copyFrom:2) from:handle.
-			].
-		    ].
-		    initAddr isNil ifTrue:[
-			Transcript showCR:('no symbol: ',aName,' in ', pathName).
-		    ] ifFalse:[
-			Verbose ifTrue:[
-			    ('ObjectFileLoader [info]: calling init at:' , (initAddr printStringRadix:16)) infoPrintCR
-			].
-			self
-			    performModuleInitAt:initAddr
-			    invokeInitializeMethods:invokeInitializeMethods
-			    for:nil
-			    identifyAs:handle.
-			didInit := true.
-		    ]
-		].
-	    ].
-	]
+        "look for explicit C-init (xxx__Init) function
+         This is used in C object files"
+
+        initAddr := self findFunction:initFunctionName suffix:'__Init' in:handle.
+        initAddr notNil ifTrue:[
+            isCModule := true.
+
+            OSSignalInterrupt handle:[:ex |
+                Logger error:'hard error in initFunction of class-module: %1' with:pathName.
+                status := #initFailed.
+            ] do:[
+                cRetVal := self
+                    saveCallInitFunctionAt:initAddr
+                    in:pathNameOrFilename
+                    specialInit:false
+                    forceOld:true
+                    interruptable:false
+                    argument:0
+                    identifyAs:handle
+                    returnsObject:false.
+                (cRetVal < 0) ifTrue:[
+                    Verbose ifTrue:[
+                        'ObjectFileLoader [warning]: init function returns failure ... unload' infoPrintCR.
+                    ].
+                    status := #initFailed.
+                ] ifFalse:[
+                    didInit := true.
+                ]
+            ]
+        ] ifFalse:[
+            status := #noInitFunction.
+
+            "look for any init-function(s); call them all"
+            Verbose ifTrue:[
+                'ObjectFileLoader [info]: no good init functions found; looking for candidates ...' infoPrintCR.
+            ].
+            initNames := self namesMatching:'*_Init' segment:'[tT?]' in:pathName.
+            initNames notNil ifTrue:[
+                initNames do:[:aName |
+                    initAddr := self getFunction:aName from:handle.
+                    initAddr isNil ifTrue:[
+                        (aName startsWith:'_') ifTrue:[
+                            initAddr := self getFunction:(aName copyFrom:2) from:handle.
+                        ].
+                    ].
+                    initAddr isNil ifTrue:[
+                        Transcript showCR:('no symbol: ',aName,' in ', pathName).
+                    ] ifFalse:[
+                        Verbose ifTrue:[
+                            ('ObjectFileLoader [info]: calling init at:' , (initAddr printStringRadix:16)) infoPrintCR
+                        ].
+                        self
+                            performModuleInitAt:initAddr
+                            invokeInitializeMethods:invokeInitializeMethods
+                            for:nil
+                            identifyAs:handle.
+                        didInit := true.
+                    ]
+                ].
+            ].
+        ]
     ].
 
     (invokeInitializeMethods and:[didInit not]) ifTrue:[
-	status == #noInitFunction ifTrue:[
-	    msg := 'no classLib init function found; assume load ok'
-	] ifFalse:[
-	    (status ~~ #registrationFailed
-		and:[status ~~ #initFailed
-		and:[status ~~ #missingClass
-		and:[status ~~ #versionMismatch]]])
-	    ifTrue:[
-		self listUndefinedSymbolsIn:handle.
-	    ].
-
-	    Verbose ifTrue:[
-		'ObjectFileLoader [warning]: unloading, since init failed ...' infoPrintCR.
-	    ].
-
-	    "/ give caller a chance to prevent unloading (to register later, when a prerequisite class comes)
-	    status == #missingClass ifTrue:[
-		doNotUnload := (SuperClassMissingErrorNotification query ? false).
-	    ] ifFalse:[
-		status == #registrationFailed ifTrue:[
-		    doNotUnload := (RegistrationFailedErrorNotification query ? false).
-		] ifFalse:[
-		    doNotUnload := false.
-		].
-	    ].
-	    doNotUnload ifFalse:[
-		self unloadDynamicObject:handle.
-		Verbose ifTrue:[
-		    'ObjectFileLoader [info]: unloaded.' infoPrintCR.
-		].
-		handle := nil.
-	    ].
-
-	    status == #initFailed ifTrue:[
-		msg := 'module not loaded (init function signaled failure).'
-	    ] ifFalse:[
-		status == #missingClass ifTrue:[
-		    msg := 'module not loaded (superclass missing: ' , (info at:2) , ').'
-		] ifFalse:[
-		    status == #registrationFailed ifTrue:[
-			msg :=  'module registration failed (incompatible object or missing superclass)'
-		    ] ifFalse:[
-			status == #versionMismatch ifTrue:[
-			    msg :=  'module registration failed (class version mismatch ' , (info at:2) printString , ')'
-			] ifFalse:[
-			    (self namesMatching:'*__sepInitCode__*' segment:'[tT?]' in:pathName) notNil ifTrue:[
-				msg := 'module not loaded (unknown error reason).'
-			    ] ifFalse:[
-				msg := 'module not loaded (no _Init entry in object file ?).'
-			    ]
-			]
-		    ].
-		].
-	    ].
-	].
-	Verbose ifTrue:[
-	    Logger debug:'%1: %2' with:pathNameOrFilename asFilename baseName with:msg.
-	].
+        status == #noInitFunction ifTrue:[
+            msg := 'no classLib init function found; assume load ok'
+        ] ifFalse:[
+            (status ~~ #registrationFailed
+                and:[status ~~ #initFailed
+                and:[status ~~ #missingClass
+                and:[status ~~ #versionMismatch]]])
+            ifTrue:[
+                self listUndefinedSymbolsIn:handle.
+            ].
+
+            Verbose ifTrue:[
+                'ObjectFileLoader [warning]: unloading, since init failed ...' infoPrintCR.
+            ].
+
+            "/ give caller a chance to prevent unloading (to register later, when a prerequisite class comes)
+            status == #missingClass ifTrue:[
+                doNotUnload := (SuperClassMissingErrorNotification query ? false).
+            ] ifFalse:[
+                status == #registrationFailed ifTrue:[
+                    doNotUnload := (RegistrationFailedErrorNotification query ? false).
+                ] ifFalse:[
+                    doNotUnload := false.
+                ].
+            ].
+            doNotUnload ifFalse:[
+                self unloadDynamicObject:handle.
+                Verbose ifTrue:[
+                    'ObjectFileLoader [info]: unloaded.' infoPrintCR.
+                ].
+                handle := nil.
+            ].
+
+            status == #initFailed ifTrue:[
+                msg := 'module not loaded (init function signaled failure).'
+            ] ifFalse:[
+                status == #missingClass ifTrue:[
+                    msg := 'module not loaded (superclass missing: ' , (info at:2) , ').'
+                ] ifFalse:[
+                    status == #registrationFailed ifTrue:[
+                        msg :=  'module registration failed (incompatible object or missing superclass)'
+                    ] ifFalse:[
+                        status == #versionMismatch ifTrue:[
+                            msg :=  'module registration failed (class version mismatch ' , (info at:2) printString , ')'
+                        ] ifFalse:[
+                            (self namesMatching:'*__sepInitCode__*' segment:'[tT?]' in:pathName) notNil ifTrue:[
+                                msg := 'module not loaded (unknown error reason).'
+                            ] ifFalse:[
+                                msg := 'module not loaded (no _Init entry in object file ?).'
+                            ]
+                        ]
+                    ].
+                ].
+            ].
+        ].
+        Verbose ifTrue:[
+            Logger debug:'%1: %2' with:pathNameOrFilename asFilename baseName with:msg.
+        ].
     ].
 
     isCModule ifFalse:[
-	Smalltalk flushCachedClasses.
-	Class flushSubclassInfo.
-
-	(definitionClass notNil and:[definitionClass isLoaded]) ifTrue:[
-	    definitionClass
-		checkForLoad;                           "/ raise exception if not supported on platform / not licensed
-		loadAllClassesAsAutoloaded:true;
-		loadPreRequisitesAsAutoloaded:true;     "/ load non-mandatory prerequisites
-		projectIsLoaded:true.                   "/ this performs the postLoadAction, too.
-	].
-	Smalltalk isInitialized ifTrue:[
-	    "really don't know, if and what has changed ...
-	     ... but assume, that new classes have been installed."
-	    Smalltalk changed:#postLoad.
-	].
+        Smalltalk flushCachedClasses.
+        Class flushSubclassInfo.
+
+        (definitionClass notNil and:[definitionClass isLoaded and:[definitionClass isObsolete not]]) ifTrue:[
+            [                
+                definitionClass checkForLoad.   "/ raise exception if not supported on platform / not licensed
+            ] on:PackageLoadError do:[:ex|
+                self unloadObjectFileAndRemoveClasses:pathName.
+                ex reject.      
+                ^ nil.
+            ].
+            definitionClass 
+                initialize;
+                preLoadAction;
+                loadMandatoryPreRequisitesAsAutoloaded:false.
+        ].
+        Smalltalk isInitialized ifTrue:[
+            "really don't know, if and what has changed ...
+             ... but assume, that new classes have been installed."
+            Smalltalk changed:#postLoad.
+        ].
     ].
     ^ handle
 
     "Modified: / 15-11-2010 / 13:19:26 / cg"
     "Modified (comment): / 13-02-2017 / 20:27:55 / cg"
+    "Modified (format): / 17-10-2019 / 14:35:07 / Stefan Vogel"
 !
 
 unloadAllObsoleteObjectFiles
@@ -1531,7 +1542,7 @@
     "Modified: 5.12.1995 / 18:16:52 / cg"
 !
 
-unloadObjectFile:aFileName
+unloadObjectFile:aFilename
     "unload an object file (.o-file) from the image.
      DANGER ALERT: currently, you have to make sure that no references to
      objects of this module exist - in future versions, the system will keep
@@ -1540,21 +1551,20 @@
 
     |handle|
 
-    LoadedObjects notNil ifTrue:[
-	handle := LoadedObjects at:aFileName ifAbsent:nil
-    ].
+    handle := self handleForDynamicObject:aFilename.
     handle isNil ifTrue:[
-	('ObjectFileLoader [info]: oops - file to be unloaded was not loaded dynamically (', aFileName , ')') infoPrintCR.
-	^ self
+        Logger info:'oops - file to be unloaded was not loaded dynamically (%1)' with:aFilename.
+        ^ self
     ].
 
     "/ call the modules deInit-function and unload...
     self unloadDynamicObject:handle
 
     "Modified: / 06-12-2006 / 18:19:13 / cg"
+    "Modified: / 17-10-2019 / 13:35:52 / Stefan Vogel"
 !
 
-unloadObjectFileAndRemoveClasses:aFileName
+unloadObjectFileAndRemoveClasses:aFilename
     "unload an object file (.o-file) from the image and remove all
      corresponding classes from the system.
      DANGER ALERT: currently, you have to make sure that no references to
@@ -1564,30 +1574,29 @@
 
     |handle|
 
-    LoadedObjects notNil ifTrue:[
-	handle := LoadedObjects at:aFileName ifAbsent:nil
-    ].
+    handle := self handleForDynamicObject:aFilename.
     handle isNil ifTrue:[
-	('ObjectFileLoader [info]: oops - file to be unloaded was not loaded dynamically (', (aFileName ? 'unknown-file') , ')') infoPrintCR.
-	^ self
+        Logger info:'oops - file to be unloaded was not loaded dynamically (%1)' with:aFilename.
+        ^ self
     ].
     handle isClassLibHandle ifFalse:[
-	self error:'Module is not a classLib module. Proceed to unload anyway' mayProceed:true.
+        self error:'Module is not a classLib module. Proceed to unload anyway' mayProceed:true.
     ].
 
     "/ remove the classes ...
     Class withoutUpdatingChangesDo:[
-	handle classes do:[:eachClass |
-	    (eachClass notNil and:[eachClass isMeta not]) ifTrue:[
-		eachClass removeFromSystem.
-	    ]
-	]
+        handle classes do:[:eachClass |
+            (eachClass notNil and:[eachClass isMeta not]) ifTrue:[
+                eachClass removeFromSystem.
+            ]
+        ]
     ].
 
     "/ call the modules deInit-function and unload...
     self unloadDynamicObject:handle
 
     "Modified: / 06-12-2006 / 18:19:19 / cg"
+    "Modified: / 17-10-2019 / 13:38:01 / Stefan Vogel"
 ! !
 
 !ObjectFileLoader class methodsFor:'dynamic object queries'!