0

I have a C code block in my org-mode document like the following:

#+begin_src C :exports both
#include "my_header.h"

int main(void)
{
    function_from_my_header();
    return 0;
}
#+end_src

When I have point inside the code block and C-c C-c to compile + generate results, I get the following error.

/var/folders/bc/2wq0dn651ys844kp5cz459mc0000gn/T/babel-SktA20/C-src-RnWgKS.c:8:10: fatal error: 'my_header.h' file not found
#include "my_header.h"
         ^~~~~~~~~~~~~
1 error generated.
zsh:1: permission denied: /var/folders/bc/2wq0dn651ys844kp5cz459mc0000gn/T/babel-SktA20/C-bin-DWq2ho

How do I get org-mode to recognize the header file (which is contained in the same directory as the org file?

It is worth noting: everything has worked fine so far if I don't have (custom) headers (e.g., includes for stdio.h etc. work fine). It is also worth noting that if I save the source code block to a file and compile using gcc, then the file compiles fine. Ergo, it seems the missing piece is determining how to get org-mode to recognize my_header.h, which lies in the same directory as the org file itself.


Edit: Solved

I did as NickD suggested but still got an error. To be precise, I have the three files

  • my_header.c
#include <stdio.h>
#include "my_header.h"

void my_function(void)
{
    printf("I can C clearly now.\n");
}
  • my_header.h (contains only the prototype for my_function.
  • my_test.c
#include "my_header.h"

int main(void)
{
    my_function();
    return 0;
}

When I compile and link from the command line (from within the directory in which these files reside), I run:

gcc my_test.c my_header.c -o my_test && ./my_test

Everything works perfectly.

Now, if I run the following code block from within an org-mode document (residing in the same directory):

#+begin_src C :flags -I .
#include "my_header.h"

int main(void)
{
    my_function();
    return 0;
}
#+end_src

I get the following error message from the compiler:

Undefined symbols for architecture x86_64:
  "_my_function", referenced from:
      _main in C-src-fboHG7-40f2c1.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
zsh:1: no such file or directory: /var/folders/bc/2wq0dn651ys844kp5cz459mc0000gn/T/babel-SktA20/C-bin-9wLHvS

The fix (in addition to setting :flags -I. was to also set :includes my_header.c

The following works perfectly for me when I C-c C-c in org:

#+begin_src C :flags -I . :includes my_header.c
int main(void)
{
    my_function();
    return 0;
}
#+end_src

Question summary

How do I get org-mode to recognize the header file (which is contained in the same directory as the org file?

You don't. You point it to the source file corresponding to the header (i.e., my_header.c) by include-ing my_header.c.

Why is this the expected behaviour? My understanding is that this flag creates an #include "my_header.c" line in the temporary .c file, and that this is not standard practice when writing C code (one usually includes the .h file).

1
  • 1
    Please do NOT change the question after the fact: ask a different question.
    – NickD
    Commented Jan 19, 2021 at 13:07

2 Answers 2

2

You need to arrange that gcc is called with the flag -I . that tells the preprocessor to look in the current directory (as well as the default directories). You can do that with

#+begin_src C :exports both :flags -I .
#include "my_header.h"

int main(void)
{
    function_from_my_header();
    return 0;
}
#+end_src

Why that is needed and why you don't need anything like that when you invoke gcc from the command line is a bit subtle: Org babel creates a temporary file /var/folders/bc/2wq0dn651ys844kp5cz459mc0000gn/T/babel-SktA20/C-src-RnWgKS.c (as you can see in the error message), with the source code from the code block inserted, but note it's in some temporary directory, not in the directory where your Org mode file and my_header.h are. So the compilation fails. Try copying your C file to some other directory and then on the command line saying gcc -o /path/to/other/directory/foo /path/to/other/directory/foo.c: it will fail the same way.

By giving it the -I . flag, you are saying "search for include files in the current directory, as well as in the standard include directories", i.e. you are effectively executing gcc -o /path/to/other/directory/foo -I . /path/to/other/directory/foo.c from the directory where your Org mode file and your my_header.h file are: since your current directory does contain my_header.h, the preprocessor can find it and everything works.

There are several other header arguments for C code blocks that are described in the relevant Babel Language page on Worg (:libs e.g. will be useful whenever you try to link with an external library). And if you venture to other languages, you might want to look at their language-specific pages.

5
  • I updated my question to reflect new developments. I can get it to work - 50% due to your input (thank you!). I am confused about the remaining 50%. Why should it be necessary to :includes the my_header.c file? Commented Jan 19, 2021 at 5:16
  • Please don't change the question after it is answered: ask a different questions instead.
    – NickD
    Commented Jan 19, 2021 at 17:25
  • The original question is "How do I get org-mode to recognize a quoted header file?" and the uninformative answer (from what I can tell) is: "you don't. you point it to the header's source file". Asking for an explanation of that behaviour seems within scope for providing an informative answer. Commented Jan 20, 2021 at 16:40
  • The original question was: "Why do I get an error when I use a header file in the current directory ?". I explained why in detail. You then added separate compilation into the question. That is now a different question which should be posted separately.
    – NickD
    Commented Jan 20, 2021 at 18:32
  • The original question is the one I've quoted (simply view my question above the Edit headline or read the edit history to confirm). Is "recognize" ambiguous somehow? Indeed, if I point org to the right directory using the -I. flag as you suggest, then the compiler recognizes the existence of the .h file but fails to compile because it still does not recognize the .c file. Commented Jan 21, 2021 at 17:49
1

The correct solution involves a step beyond what was described in NickD's answer.

The following is correct - both in terms of C style and org-mode style.

#+begin_src C :flags -I. my_header.c
#include "my_header.h"

int main(void)
{
    function_from_my_header();
    return 0;
}
#+end_src

Equivalently, one could write

#+begin_src C :flags -I. my_header.c :includes my_header.h
function_from_my_header();
#+end_src

This can be gleaned from how the #+CALL is described in the org manual, noting that the call to gcc should look like:

gcc -o <executable_name> <code_block_name.c> my_header.c -I.

(In particular, my_header.c needs to appear in the call to gcc, and :flags is the appropriate place to include that. Importantly, my_header.c should not be placed in the :includes header arg. This is bad C practice and can have unintended consequences.)

Your Answer

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

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