Author Topic: Demand Loading Files - a solution  (Read 8715 times)

0 Members and 1 Guest are viewing this topic.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Demand Loading Files - a solution
« on: April 19, 2012, 09:53:34 PM »
Some people are having problems loading files so they are available when needed.

The options are either to load everything at the start
or to have some sort of demand-load mechanism in place.

There are issues with the AutoCAD 2013 Startup Suite loading lsp files
so I thought I'd post a modified version of the mechanism I have used
sucessfully for about 10 years.

The sample files are included in a Zip ...
just drop the lot into a folder that is on the AutoCAD path.

In AutoCAD menuLoad the partial menu 'MyPersonalMenu.MNU'
Once the partial menu is loaded it will load each time you open a session.

The file 'MyPersonalMenu.MNL' will load automatically when the MNU loads.
This file is used to load files I need in each document namespace
and to define 'stubs' for any functions/commands I want to be DEMAND-loaded.
The file 'KDUB_DemandLoader.LSP' has documentation
and the samples in MyPersonalMenu.MNL can be followed.

If you dont want the files loaded just unload the partial menu
or comment out the stub declaration in the .MNL file.

As you develop new functions/command just add the relevant AutoLoad stub
to the MNL file and distribute it with the new/revised code files.

The System works with compiled files.
It works for Commands and methods.
It allows stubs to be defined with parameters.

Using this methodology initial load time and memory use is reduced considerably
... code files are not loaded untill thy are needed.

I look forward to Comments

Regards
Kerry
Code: [Select]
// MyPersonalMenu.MNU
//============================================================================
// $Header: $
//
// codeHimBelonga kdub@theSwamp 2012.04.20

***MENUGROUP=MYPERSONALMENU   
***POP19
 [KDUB_TestMenu_Sample]
 [Test 5]^C^CTest5;
 [Test 3]^C^CTest3;
***TOOLBARS
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; MyPersonalMenu.MNL
  3. ;;============================================================================
  4. ;; KDUB:AutoLSPLoad is defined in ..../Support/acad2012doc.lsp
  5. (or (vl-symbol-value 'KDUB:AutoLSPLoad)
  6.     (load "KDUB_DemandLoader.LSP")
  7. )
  8. (or (vl-symbol-value 'test00a) (load "Test00.lsp"))
  9.  
  10. (prompt "\n   MyPersonalMenu.MNL Build 2012.04.20 ....")
  11.  
  12.  
  13. (KDUB:AutoLSPLoad "Test01.lsp" '(("test1a") ("Test1b")))
  14. (KDUB:AutoLSPLoad "Test02.lsp" '(("c:test2")))
  15. (KDUB:AutoLSPLoad
  16.    "Test03"
  17.    '(("c:test3") ("test3a") ("test3B" "Str1" "Str2"))
  18. )
  19. ;; command alias definition
  20. (defun c:aaaa ()
  21.    (ThisIsAReallyLongMethodNameThatIsUnlikelyToBeDuplicated)
  22.    (princ)
  23. )
  24. (KDUB:AutoLSPLoad
  25.    "Test04"
  26.    '(("ThisIsAReallyLongMethodNameThatIsUnlikelyToBeDuplicated"))
  27. )
  28.  
  29. (KDUB:AutoLSPLoad "Test05.FAS" '(("c:test5")))
  30.  
  31.  
  32. (prompt "\n   .... loaded")
  33.  
Code - Auto/Visual Lisp: [Select]
  1. ;;;============================================================================
  2. ;; KDUB_DemandLoader.LSP
  3. ;|  KDUB:autolspload
  4. Usage and Notes:
  5. Adapted by kwb  2002 Aug 29
  6. from posting to newsgroup by Kevin J. Nehls 3-31-2002
  7.         (KDUB:autolspload "<filename>"
  8.                   '(("<func1_name>" "<arg1>" "<arg2>") ("<func2_name>" "<arg1>"))
  9.         )
  10.         (KDUB:autoarxload "<filename>" '(("<func1_name>" "<arg1>") ("<func2_name>")))
  11. Example 1:
  12.         (KDUB:AutoLSPLoad "lspExample1" '(("C:cmd1") ("C:cmd2")))
  13. Example 2:
  14.         (KDUB:AutoLSPLoad "lspExample2" '(("KDUB:EX2" "str1" "str2" "real" "int")))
  15. KDUB:AutoARXLoad works exactly the same way as KDUB:AutoLSPLoad only for ARX files
  16.  
  17. Just add your KDUB:AutoxxxLoad statements to the end of this file or have
  18. this file load
  19. another file which has these statements.
  20.  
  21.   1) Default support for VLX and FAS files without having to specify
  22.      the file extension.
  23.   2) It can KDUB:AutoXXXLoad any function with any number of arguments.
  24.   3) It won't throw you into an infinite loop if the file loaded
  25.      doesn't redefine the function/command that is to be called.
  26.      --AutoCAD's AutoLoader will do this.
  27.      If this happens you now get a message telling you where the
  28.      error occured.
  29.      --AutoCAD's AutoLoader does not do this.
  30.   4) If you want to autoload a command line command you have to
  31.      prefix it with C:, see Example 1.
  32.   5) To have multiple fuctions/commands autoloaded from the same
  33.      file, just add the additional functions as shown in the examples
  34.   6) There is no error handling in this AutoLoader.  The only reason you
  35.      would have it is if the file you were loading was "self-executing".
  36.      I have my functions/routines handle the error handling and don't
  37.      need the AutoLoader to do this.
  38.   7) This AutoLoader currently needs to have AutoCAD 2000 or newer installed
  39.      to work just becuase of the use of (vl-filename-extension).  You can
  40.      easily add support for just about all previous versions that support
  41.      the AutoLISP functions used by either removing that or just looking
  42.      at the last four chars and determining if it's an extension or not.
  43. |;
  44.  
  45. (defun KDUB:autoloader
  46.        (apptyp cmdfile cmdlst / cmdnam arglst cmdpfile)
  47.    (setq cmdpfile (strcat "\"" cmdfile "\""))
  48.    (mapcar
  49.       (function
  50.          (lambda (cmdlst1)
  51.             (setq cmdnam (car cmdlst1)
  52.                   varlst (cdr cmdlst1)
  53.                   arglst ""
  54.             )
  55.             (if varlst
  56.                (foreach var varlst
  57.                   (setq arglst (strcat arglst var " "))
  58.                )
  59.             )
  60.             (if (not (eval (read cmdnam)))
  61.                (eval
  62.                   (read
  63.                      (strcat
  64.                         "(defun "
  65.                         cmdnam
  66.                         " ("
  67.                         arglst
  68.                         " / tst)"
  69.                         "(princ \"\nInitializing....\")"
  70.                         "(setq tst "
  71.                         cmdnam
  72.                         ")"
  73.                         "(if (KDUB:autoloaderFindFile "
  74.                         cmdpfile
  75.                         ")"
  76.                         (if (= (strcase apptyp) "LSP")
  77.                            (strcat "(progn (load " cmdpfile ")")
  78.                            (strcat "(progn (ARXload "
  79.                                    cmdpfile
  80.                                    ")"
  81.                            )
  82.                         )
  83.                         "(if (/= tst "
  84.                         cmdnam
  85.                         ")"
  86.                         "("
  87.                         cmdnam
  88.                         " "
  89.                         arglst
  90.                         ")"
  91.                         "(KDUB:autoloaderNoReDefun "
  92.                         "\""
  93.                         apptyp
  94.                         "\""
  95.                         " "
  96.                         "\""
  97.                         cmdnam
  98.                         "\""
  99.                         ")
  100.                                                 )
  101.                                                 )"
  102.                         "(KDUB:autoloaderNoFile "
  103.                         cmdpfile
  104.                         ")
  105.                                 )"
  106.                         ")"
  107.                      )
  108.                   )
  109.                )
  110.             )
  111.          )
  112.       )
  113.       cmdlst
  114.    )
  115.    nil
  116. )
  117.  
  118. ;;;---------------------------------------------------------------------------------
  119. (DEFUN KDUB:autoloaderFindFile (appnam)
  120.   (OR (FINDFILE (STRCAT appnam ".vlx"))
  121.       (FINDFILE (STRCAT appnam ".fas"))
  122.       (FINDFILE (STRCAT appnam ".lsp"))
  123.       (FINDFILE (STRCAT appnam ".arx"))
  124.       (FINDFILE appnam)
  125.   )
  126. )
  127. ;;;---------------------------------------------------------------------------------
  128. (DEFUN KDUB:autoloaderNoFile (appnam)
  129.   (ALERT (STRCAT "The file \""
  130.                  appnam
  131.                  "\""
  132.                  (IF (NOT (VL-FILENAME-EXTENSION appnam))
  133.                    "(.vlx/.fas/.lsp/.arx) "
  134.                    " "
  135.                  )
  136.                  "was not found in your search path folders.\n"
  137.                  "Check the installation of the support files and try again."
  138.          )
  139.   )
  140.   (PRINC)
  141. )
  142. ;;;---------------------------------------------------------------------------------
  143. (DEFUN KDUB:autoloaderNoReDefun (apptyp cmdnam)
  144.   (ALERT (STRCAT "Syntax error in KDUB:Auto"
  145.                  (STRCASE apptyp)
  146.                  "Load for function/command:\n\n\""
  147.                  "\""
  148.                  (STRCASE cmdnam)
  149.                  "\""
  150.          )
  151.   )
  152. )
  153. ;;;---------------------------------------------------------------------------------
  154. (DEFUN KDUB:autolspload (appnam cmdlst) (KDUB:autoloader "lsp" appnam cmdlst))
  155. ;;;---------------------------------------------------------------------------------
  156. (DEFUN KDUB:autoarxload (appnam cmdlst) (KDUB:autoloader "arx" appnam cmdlst))
  157. ;;;---------------------------------------------------------------------------------
  158.  
  159.         (princ)
  160.  
  161.  
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; Test00.LSP
  3. ;; library file containing routines and functions to be loaded in each drawing
  4. ;;============================================================================
  5. (defun test00a () (alert "This is function test00a") (princ))
  6.  
  7.  
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; Test02.LSP
  3. ;;============================================================================
  4. (defun c:test2 () (alert "This is command test2") (princ))
  5.  
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; Test03.LSP
  3. ;;============================================================================
  4. (defun test3a () (test3b "Fred" "Bloggs") (princ))
  5. ;;============================================================================
  6. (defun c:Test3 ()
  7.    (alert "This is command test3")
  8.    (test3a)  
  9.    (princ)
  10. )
  11.  
  12. ;;============================================================================
  13. (defun test3B (FirstStr LastStr / result)
  14.    (setq result (strcat FirstStr " " LastStr))
  15.    (alert
  16.       (strcat "This is function test3b" "\n Result is :" result)
  17.    )
  18.    (princ)
  19. )
  20.  
  21. ;;============================================================================
  22.  
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; Test04.LSP
  3. ;;============================================================================
  4. (defun ThisIsAReallyLongMethodNameThatIsUnlikelyToBeDuplicated
  5.        ()
  6.    (alert
  7.       (strcat
  8.          "Function :  "
  9.          "ThisIsAReallyLongMethodNameThatIsUnlikelyToBeDuplicated"
  10.          "\n"
  11.          "Loaded from Test04.LSP"
  12.       )
  13.    )
  14.    (princ)
  15. )
  16.  
  17.  
Code - Auto/Visual Lisp: [Select]
  1. ;;codeHimBelonga kdub@theSwamp
  2. ;; Test05.LSP
  3. ;;============================================================================
  4. ;; (vlisp-compile 'st "K:\\TEST\\TEST05.lsp" "K:\\TEST\\TEST05.fas")
  5.  
  6. ;;============================================================================
  7. (defun c:test5 () (alert "This is command test5") (princ))
  8.  

... The source :
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #1 on: April 20, 2012, 04:18:16 AM »
Very similar to what I'm doing here: http://caddons.svn.sourceforge.net/viewvc/caddons/Caddons.MNL?revision=64&view=markup
(Line 182)

The only major difference is that I'm obtaining the path from the partial CUI file using the function on line 106. That way my codes don't even need to be on a support path. Only setup required is to menuload the CUI.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Demand Loading Files - a solution
« Reply #2 on: April 20, 2012, 04:58:37 AM »

If memory serves, I've tried something like that too.

I believe that anyone who uses this methodology will
have a significant amount of files ( code and blocks) to
deal with so it's a more transparent solution to just add
additional paths to the config  path list.

kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

VovKa

  • Water Moccasin
  • Posts: 1632
  • Ukraine
Re: Demand Loading Files - a solution
« Reply #3 on: April 20, 2012, 12:45:46 PM »
i think one can omit searching for files with different extensions
an abstract from the help topic on LOAD
Quote
Arguments

filename

A string that represents the file name. If the filename argument does not specify a file extension, load adds an extension to the name when searching for a file to load. The function will try several extensions, if necessary, in the following order:

.vlx
.fas
.lsp
As soon as load finds a match, it stops searching and loads the file.


efernal

  • Bull Frog
  • Posts: 206
Re: Demand Loading Files - a solution
« Reply #4 on: April 20, 2012, 02:48:31 PM »
in my acaddoc.lsp i write something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun c:teste1 ()(load "C:\\Testes\\Teste1" 0)(c:teste1)(princ))
  2. (defun c:teste2 ()(load "C:\\Testes\\Teste2" 0)(c:teste2)(princ))
  3. (defun c:teste3 ()(load "C:\\Lisps0\\Teste3" 0)(c:teste3)(princ))
  4. ;; etc...
  5.  
  6.  

and my routines will be available...
e.fernal

cmwade77

  • Swamp Rat
  • Posts: 1443
Re: Demand Loading Files - a solution
« Reply #5 on: April 20, 2012, 04:38:44 PM »
In AutoCAD 2013, the problem isn't with the demand loading it's self, it's that the acad2013doc.lsp doesn't get loaded with AutoCAD starts. If you rename this file to acad2012doc.lsp it will load just fine. I would definitely call this a major bug, especially when it is something so overly simple for AutoDesk to fix.

I instead have simply put the contents into a LISP file that loads every time I open a drawing, because it is in my enterprise CUI file.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #6 on: April 21, 2012, 08:50:25 AM »
in my acaddoc.lsp i write something like this:

Code - Auto/Visual Lisp: [Select]
  1. (defun c:teste1 ()(load "C:\\Testes\\Teste1" 0)(c:teste1)(princ))
  2. (defun c:teste2 ()(load "C:\\Testes\\Teste2" 0)(c:teste2)(princ))
  3. (defun c:teste3 ()(load "C:\\Lisps0\\Teste3" 0)(c:teste3)(princ))
  4. ;; etc...
  5.  
  6.  
That's exactly the stub function my custom built "AutoLoader" generates on the fly. (Minus the princ though).

I've just realized after looking at your code: If the file is not found, this stub function will loop infinitely. It needs something like an if statement:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test1 () (if (load "C:\\Tests\\Test1" nil) (c:test1) (princ "File cannot be found")) (princ))
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

Lee Mac

  • Seagull
  • Posts: 12916
  • London, England
Re: Demand Loading Files - a solution
« Reply #7 on: April 21, 2012, 09:02:49 AM »
I've just realized after looking at your code: If the file is not found, this stub function will loop infinitely. It needs something like an if statement:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:test1 () (if (load "C:\\Tests\\Test1" nil) (c:test1) (princ "File cannot be found")) (princ))

There is also another condition that will cause this construct to loop indefinitely: consider the case in which the load function finds a LISP file called "test1.lsp", however this file does not contain the function definition for 'c:test1'.

This has been commonly experienced when inadvertently saving a LISP file with the same name as an Express Tools LISP file, however, with different command syntax to such Express Tools program, causing the Express Tools autoload to loop indefinitely.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #8 on: April 21, 2012, 09:22:03 AM »
OK, so the stub function should rather be something like this then:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:Test1 ( / old)
  2.   (setq old c:Test1)
  3.   (if (load "C:\\Test\\Test1" nil)
  4.     (if (eq old c:Test1)
  5.       (princ "The file found does not contain a Test1 command")
  6.       (c:Test1))
  7.     (princ "The Test1 file could not be found"))
  8.   (princ))
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

VovKa

  • Water Moccasin
  • Posts: 1632
  • Ukraine
Re: Demand Loading Files - a solution
« Reply #9 on: April 21, 2012, 09:30:27 AM »
OK, so the stub function should rather be something like this then:
Code - Auto/Visual Lisp: [Select]
  1. (defun c:Test1 ( / old)
  2.   (setq old c:Test1)
  3.   (if (load "C:\\Test\\Test1" nil)
  4.     (if (eq old c:Test1)
  5.       (princ "The file found does not contain a Test1 command")
  6.       (c:Test1))
  7.     (princ "The Test1 file could not be found"))
  8.   (princ))
be careful with (if (load "C:\\Test\\Test1" nil) it will fail if the last expression if the file returns nil
the sample content of Test1.lsp
Code: [Select]
(defun redbutton () (blah) (blah) (blah))
(prompt "redbutton loaded")

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #10 on: April 21, 2012, 09:36:15 AM »
Good point!

So something like this then. In your MNL you should have one of these
Code: [Select]
(defun RunAutoLoaded (func args filename / old new)
  (setq old (eval (read func)))
  (if (findfile filename)
    (progn
      (load filename nil)
      (if (eq old (setq new (eval (read func))))
        (princ (strcat "The " func " function is not contained in the " filename " file."))
        ((cons new args))))
    (princ (strcat "The " filename " file could not be found.")))
  (princ))
Then your stubs can be something like these:
Code: [Select]
(defun c:Test1 (/) (RunAutoLoaded "c:Test1" nil "C:\\Test\\Test1"))

(defun MyFunc (Arg1 Arg2 / ) (RunAutoLoaded "MyFunc" (list Arg1 Arg2) "C:\\Test\\Test1"))
« Last Edit: April 21, 2012, 09:44:17 AM by irneb »
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

VovKa

  • Water Moccasin
  • Posts: 1632
  • Ukraine
Re: Demand Loading Files - a solution
« Reply #11 on: April 21, 2012, 09:49:34 AM »
Code: [Select]
(findfile "C:\\Test\\Test1") will not find C:\\Test\\Test1.lsp or whatever the extension is

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #12 on: April 21, 2012, 09:58:26 AM »
You are correct. See my codes on the Caddons SVN, link in Reply #2. Notice the Caddons:Load function on line 136 - I've redone the normal load just for such reason. Perhaps I should've redone a FindFile idea rather.

Anyhow another point, why I originally omitted the princ at the end of the stub:
Code: [Select]
(defun RunAutoLoaded (func args filename / old new return)
  (setq old (eval (read func)))
  (if (findfile filename)
    (progn
      (load filename nil)
      (if (eq old (setq new (eval (read func))))
        (princ (strcat "The " func " function is not contained in the " filename " file."))
        (setq return ((cons new args)))))
    (princ (strcat "The " filename " file could not be found.")))
  (if (eq return (princ))
    (princ)
    return))

My autoloader is supposed to work with both command defuns and defuns obtaining arguments, but also defuns returning values. So I couldn't just send a princ at the end - that would omit the intended return value.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

irneb

  • Water Moccasin
  • Posts: 1794
  • ACad R9-2016, Revit Arch 6-2016
Re: Demand Loading Files - a solution
« Reply #13 on: April 21, 2012, 09:59:19 AM »
Anyhow, thanks all. This gave me food for thought. I'll have to rethink some of those functions in Caddons.
Common sense - the curse in disguise. Because if you have it, you have to live with those that don't.

VovKa

  • Water Moccasin
  • Posts: 1632
  • Ukraine
Re: Demand Loading Files - a solution
« Reply #14 on: April 21, 2012, 10:13:15 AM »
i used to use this for loading
Quote
(defun vk_Load (FileName / OnFailure Status)
    (setq OnFailure (vk_RandNum)
     Status    (vl-catch-all-apply 'load (list FileName OnFailure))
    )
    (not (or (= Status OnFailure) (vl-catch-all-error-p Status))
    )
)