6

I found that there's a :requires (source) section, but I'm not quite sure what it does and there doesn't seem to be any documentation on it. Can someone explain what it does?

1
4

Unfortunately, use-package is not as thoroughly documented as it should be. I remember finding an explanation of this keyword at some point, but can't seem to turn it up now. Looking at the source for use-package-handler/:requires, I think what this does is make the entire use-package block conditional on the presence of the specified feature(s).

Macroexpanding a sample block seems to confirm this interpretation. Take

(use-package foo
  :requires (bar baz)
  :config
  (blah))

and call pp-macroexpand-last-sexp on it. You get this:

(if
    (not
     (member nil
             (mapcar #'featurep
                     '(bar baz))))
    (progn
      (if
          (not
           (require 'foo nil 'noerror))
          (ignore
           (message
            (format "Could not load %s" 'foo)))
        (condition-case-unless-debug err
            (blah)
          (error
           (ignore
            (display-warning 'use-package
                             (format "%s %s: %s" "foo" ":config"
                                     (error-message-string err))
                             :error))))
        t)))

If you remove the :requires line and try again, you get just the contents of the progn form. So if all of the features you listed are present at the time the block is being executed, then everything's the same. If any feature is missing, nothing is loaded whatsoever.

6
  • Oh wow okay. I was imagining perhaps it expanded to a (require 'feature) for each feature listed and then the rest of the expansion, to ensure that the features were loaded by the time the body ran. This seems like it's more for chaining for example with other packages that use :if or :when. Instead of repeating the conditions in a package that depends on those, you can just do something like :requires (a b). If their :if fail and they never load, then the one that :requires will never load either. At least, that's the only use case I can envision at the moment. – Jorge Israel Peña Jan 20 '16 at 23:34
  • 1
    By the way, I'm happy to learn about that macro expansion tool! – Jorge Israel Peña Jan 20 '16 at 23:35
  • Actually it does call (require, so it will end up loading the specified features as I was saying, but in the event that those features aren't available at the time the require runs, then the condition turns false and so the package is never loaded. Does that sound right? – Jorge Israel Peña Jan 20 '16 at 23:37
  • I think your dependency-chain use case is the most likely one. I could also see using it if you're not sure you'll have a particular package available for some reason (a multi-machine setup where your packages aren't synchronized, for instance). – Aaron Harris Jan 21 '16 at 0:49
  • The only require call I see is requiring foo, the base package, and is already past the conditional that checks for the presence of bar and baz. So that's just the use-package call itself. – Aaron Harris Jan 21 '16 at 0:55
0

@Aaron Harris' answer above is a good one. Just expanding a little on it here.

:after specifies that the main package should only load after the packages in the :after form are loaded. This can be useful when you don't want to have to declare dependencies before the main package. I use this because I like to organize my packages in alphabetical order which is often not the same as dependency order.

:requires specifies that the main package should only load after the packages in the :requires form are loaded. If they are not already loaded prior to the use-package declaration for our main package then just ignore the whole use-package form. Note that unlike when using :after, your dependencies (those packages in the :requires form must already have been loaded or the whole thing fails, it doesn't wait for dependencies to be loaded).

Example using :requires

(use-package foo
  :requires bar baz
  :config
  (blah))

macroexpands to

(progn
  (straight-use-package 'foo)
  (when
      (not
       (member nil
               (mapcar
                (function featurep)
                '(bar baz))))
    (defvar use-package--warning460
      (function
       (lambda
         (keyword err)
         (let
             ((msg
               (format "%s/%s: %s" 'foo keyword
                       (error-message-string err))))
           (display-warning 'use-package msg :error)))))
    (condition-case-unless-debug err
        (eval-after-load 'foo
          '(condition-case-unless-debug err
               (progn
                 (blah)
                 t)
             (error
              (funcall use-package--warning460 :config err))))
      (error
       (funcall use-package--warning460 :catch err)))))

Example using :after

(use-package foo
  :after bar baz
  :config
  (blah))

macroexpands to

(progn
  (straight-use-package 'foo)
  (defvar use-package--warning461
    (function
     (lambda
       (keyword err)
       (let
           ((msg
             (format "%s/%s: %s" 'foo keyword
                     (error-message-string err))))
         (display-warning 'use-package msg :error)))))
  (condition-case-unless-debug err
      (eval-after-load 'baz
        '(eval-after-load 'bar
           '(eval-after-load 'foo
              '(condition-case-unless-debug err
                   (progn
                     (blah)
                     t)
                 (error
                  (funcall use-package--warning461 :config err))))))
    (error
     (funcall use-package--warning461 :catch err))))

NOTE: The macrostep emacs package is a handy one to do the expansions.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.