10

Edit: While I'm still learning the ropes of Babel, I've read about the system-type, emacs-version, and window-system variables, which sound like they contain all the information I need to get the behavior I've described here. In fact, I could just wrap OS-specific code in conditionals when needed in code blocks. I'm wondering if this is the best way to go about this, however.


I'm using Babel to write literate configuration files for Emacs. I would like my config files to work on all of the platforms I frequently use (so basically various Linux distros and Macs), and part of this involves having settings that depend on the system (e.g., the default font I use on my Mac is different than the one I use on Linux Mint).

While I'm sure I've seen ways to recognize whether or not I'm on a Mac using elisp (and hence could wrap any system-specific settings in some kind of conditional based on this), I'm wondering if Org/Babel has some way to detect the type of system I'm on which would enable me to write different code blocks for different systems. Better yet, can this also be done for different versions of Emacs? I'm envisioning code that would look something like the following (with platform and header names being contrived examples)

#+Platform: LinuxMint
#+Emacs: GNU Emacs
#+EmacsVersion: 24+
#+BEGIN_SOURCE EMACS-LISP
    [Some configuration for Linux Mint and GNU Emacs 24+]
#+END_SOURCE

#+Platform: LinuxMint
#+Emacs: GNU Emacs
#+EmacsVersion: 22.1
#+BEGIN_SOURCE EMACS-LISP
    [Some other configuration for Linux Mint and GNU Emacs 22.1]
#+END_SOURCE

#+Platform: Mac
#+Emacs: Aquamacs
#+EmacsVersion: 24+
#+BEGIN_SOURCE EMACS-LISP
    [Some other configuration for Mac and Emacs 24+]
#+END_SOURCE

The big fish to fry is the platform, since the version of emacs and the emacsen I use can probably be inferred from this in most situations. I should mention that the platform could be coarser than what I suggest above. (I really just need to know if I'm on a Linux, Windows, or Mac distribution.) Also, if these aren't built-in features, how would I go about creating code-block headers like these?

Edit: I suppose it might also be more likely to look something like the following.

#+BEGIN_SOURCE EMACS-LISP :os Linux :emacs GNU :emacs-version 24+
    [Some configuration for Linux and GNU Emacs 24+]
#+END_SOURCE

I imagine this can be found somewhere in the documentation if it exists but I couldn't seem to find a comprehensive list of headers for code blocks. Thanks for any help you can provide!

1

1 Answer 1

12

I'm not sure how you could extract these to custom headers, but you can put raw ELISP in your header arguments. So, to conditionally tangle, you can simply put a check in your :tangle argument like so:

#+BEGIN_SRC emacs-lisp :tangle (when (eq system-type 'gnu/linux) "yes")
 (princ "I DO THINGS! (But only on Linux.)")
#+END_SRC

When the file gets tangled and the the ELISP expression "(eq system-type 'gnu/linux)" is true, it will return ""yes"", which will tangle to the default file name for that language block. You can put a filename in there as well if you prefer it. If the condition returns nil, the block does not get tangled.

Some other system-types you can play around with are "windows-nt" for some Windows OSes and "darwin" for Mac OSX. Other system information (Including "emacs-version" like you mentioned) can be fetched using the variables described on this page.

If these header arguments become unwieldy, you can possibly have a section in your .emacs where you define a few functions that only return a filename for specific system types. That way you simply need a single function call in your :tangle.


While I'm still learning the ropes of Babel, I've read about the system-type, emacs-version, and window-system variables, which sound like they contain all the information I need to get the behavior I've described here. In fact, I could just wrap OS-specific code in conditionals when needed in code blocks. I'm wondering if this is the best way to go about this, however.

When it comes to your own config file, whatever is most comfortable for you is the best option... But there are other ways to approach your problem, for example, another possibility is to have something like:

(cond
 ((eq system-type 'gnu-linux)
  (load "linux.el"))
 ((eq system-type 'darwin)
  (load "mac.el"))
 ((eq system-type 'windows-nt)
  (load "windows.el")))

...at the top of your .org file, and have each platform-specific block have a tangle argument that points to their respective file... Like ":tangle windows.el" for a piece of Windows-specific code.

Another possible strategy is to create multiple .org files for different systems, and to (org-babel-load-file ...) the one for your system using the above variables in a (cond ...) block like the one above. This way you can avoid any tangling logic altogether.

Yet another possibility would be to only write platform-independent code in your Emacs config--and to keep system-specific tweaks in your .emacs. (This is the way I do it.)


I imagine this can be found somewhere in the documentation if it exists but I couldn't seem to find a comprehensive list of headers for code blocks. Thanks for any help you can provide!

There are header arguments in the Emacs info files. You can get there with "C-h i, "mOrg Mode", and then"mSpecific header arguments"". It is also online here.

There are also language specific header arguments and other information here.. (Which is also in the Info files.)

3
  • 1
    Thank you for this fantastic write up. I'm still very new to using emacs (only been using it as my main editor for a year or so, and really actively since January). This was exactly the type of exploration of different options that I was looking for. I had no idea that headers would accept elisp like that. Now I just need to determine how to create custom ones...at least in the long run. Thanks again!
    – Dan
    Jul 27, 2015 at 19:40
  • No prob. ^^ Since Emacs is pretty heavily documented in almost every aspect, you can really learn a lot by either just exploring the documentation randomly with the C-h <thing> cords when you see something interesting, or by reading other people's code. Good luck..!
    – Archenoth
    Jul 27, 2015 at 19:55
  • It doesn work now - if you return nil you get an error. It seems "yes" or "no" are to be returned BUT it doesn't respect the following filename.
    – RichieHH
    Oct 7, 2020 at 14:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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