3

There is an eval-when-compile macro but, AFAICT, no eval-when-not-compiling or load-time-only, that would be very convenient for me now. Do you know any generic workaround?

Why do I need this: I have a package with (eval-when-compile (load "other-package")) and, in this other package, some initialisation code that is for load time only. That the code is for load time only is understood implicitly when the other-package itself is compiled, but not when it is loaded as part of compiling something else.

phs
  • 1,227
  • 7
  • 13
  • 2
    When you compile the package, you load other-package, therefore it is load time for other-package. You could try checking if byte compilation is in progress like cl--compiling-file does perhaps. – npostavs Dec 03 '17 at 12:32
  • 2
    An alternative to calling cl--compiling-file is to inspect the value of (bound-and-true-p byte-compile-current-file), which is only set during byte-compilation. – Basil Dec 03 '17 at 21:39

2 Answers2

5

EDIT:

The comment of npostavs is true. When you load "other-package" during byte compilation the test result on byte-compilation in "other-package" is negative.

You need to remember in the original package that you are byte-compiling. You can do that by let-binding:

A minimal example:

Content of the original package:

(eval-when-compile
  (let ((other-package-loading-for-compilation t))
    (load "other-package")))

Content of "other-package":

(unless (bound-and-true-p other-package-loading-for-compilation)
  (message "For initialization only"))

OLD Answer:

I assume that you have already compiled other-package. In that case

(cl-eval-when (load) ...)

in other-package works.

The doc-string of cl-eval-when:

(cl-eval-when (WHEN...) BODY...)

Control when BODY is evaluated.

If ‘compile’ is in WHEN, BODY is evaluated when compiled at top-level.

If ‘load’ is in WHEN, BODY is evaluated when loaded after top-level compile.

If ‘eval’ is in WHEN, BODY is evaluated when interpreted or at non-top-level.

From my perspective the load case description is a bit misleading. It means that BODY is evaluated when the byte-compiled library is loaded -- not only directly after byte-compilation.

You can also combine the cases. If you want BODY to be evaluated also when the source file is loaded you can use

(cl-eval-when (eval load) ...)

Tobias
  • 33,167
  • 1
  • 37
  • 77
  • @phils Thanks for the correction of my lapse. – Tobias Dec 03 '17 at 22:25
  • In my tests, this makes no difference to the problem described by phs. – Stefan Dec 04 '17 at 13:30
  • @Stefan I am afraid I didn't understand the OP's question in full. Now I edited my answer to address the OP's problem. Since some folks found the answer to be useful I keep the old content. – Tobias Dec 04 '17 at 13:50
  • thanks for the update. Note that in your updated solution, the (eval-when (load eval) is just redundant (a top-level expression of the form (unless ...) will not be evaluated by the compiler anyway). Also you might like to use bound-and-true-p to make sure the var is actually bound to a non-nil value. – Stefan Dec 04 '17 at 13:54
  • @Stefan I first thought of just using (let (other-package-loading-for-compilation) (load "other-package")) but now I changed to your version with bound-and-true-p. It is more clear. Okay, the doc says the other forms are batched together and the compiled code will be executed when the file is read. Therefore, the eval-when is redundant. Thanks for the info. – Tobias Dec 04 '17 at 14:08
3

I don't really have a solution for that problem, sadly. If you have control of other-package, the recommended way to solve those problems is to move the load-time only code into a function, because loading a package should always be "harmless" (Emacs occasionally loads Elisp files without a very strong reason, e.g. just to find out if a particular function is defined in it).

I.e. in other-package you change

(some-undesirable-load-time-code)

into

;;;###autoload
(defun other-package-initialize ()
  (some-undesirable-load-time-code))

and then the users of other-package will need to change

(require 'other-package)

into

(other-package-initialize)

when they want the initialization rather than just loading the file.

Stefan
  • 26,404
  • 3
  • 48
  • 85