Relative include files

This is a possible solution to

These questions have already been closed so I can't answer them. Say the files have the following structure

    +--include
    |   +-- xxx.h
    |   +-- yyy.h
    +-- project1
    |   +-- project1.ino
    +-- project2
    |   +-- project2.ino

I wish to include xxx.h in both projects. A simple way, from the command line (windows) is

cd project1
mklink /d include ..\include

in the code
#include "include/xxx.h"

If you only want one file, you could do something like this

cd project2
mklink xxx.h ..\include\xxx.h

in the code
#include "xxx.h"

On Linux, this can be done with ln -s.

Include files can be anywhere and you can use absolute paths if so desired. The problem is when you have a library with a .cpp file and a .h file.

The IDE will only compile .cpp files that are in certain directories.

I've never ever gotten absolute or relative paths to work. It always says no such file or directory. With symbolic links within the project directory, the code just builds.

You can generate a batch file that will copy all of the pertinent files to the sketch folder and then launch the IDE. I have tried many times to solve that problem with the IDE. It works fine with the .h files, but it will compile the first .cpp file it finds with the same name. The only reliable solution was to put both the .h and .cpp files in the sketch directory. This becomes very important if you modify a library file and make a second copy. The include order also affects the search order. The IDE does a lot of nice things, but it is not perfect.

What I am suggesting is instead of copying, make a symbolic link. That way, all the changes will be saved in the original library so you do not need to waste time copying files to and fro.

I don't think this will work with relative paths.
Arduino IDE doesn't compile your sketch in the folder where the .ino file is located. Before starting the build, IDE copies the entire folder to the temp directory, and all builds happen there, so when building, your path ..\include\xxx.h will point to a completely different location than the .h file.

will not work during the compilation.

Just tested with ln -s on linux - surprisingly, it works.

One important detail is that the sources are generated and copied into a temp directory, and the compile is done there. The .ino file is converted to an .ino.cpp. (If you have more than one .ino, they are glued together to generate a single .cpp) Then the "eligble" source files in the sketch directory tree are copied. This includes the main translation units -- .cpp, .c, .cc, .cxx, .S -- and supported headers like .h and .hpp. One hint might be whether the IDE allows creating such a file in a new tab, or complains "is not a valid extension".

Even though all the sources in the sketch's tree are copied, only those in the

  • sketch directory
    • src/ subdirectory
      • entire tree under that

are compiled. For example, if you have lib2/ as a sibling of src/, those files would be copied, so #include "lib2/whatever.h" would work, but whatever.cpp there would not be compiled. If that was needed, the sketch would fail to link -- in the C compiler sense.

A file link (hard link, symlink) should work because that is effectively a file in the sketch, and its content will be copied over. But it won't work when

  • the #include relatively navigates up back into the sketchbook, since the parent of the temp directory is another temp directory, and your files aren't there
  • running Windows and the temp directory is on a different drive than the sketchbook and the absolute path does not include the drive letter

If you enable Show verbose output during compile, it shows the temp directory in the line right after "Compiling sketch". The command is essentially: "compile .ino.cpp -o .o" to compile the generated .ino.cpp into the named object file. If you scroll all the way to the end, the temp path is there for both. For example on Windows, with extra word wrap added

"C:\\Users\\kenb4\\AppData\\Local\\arduino\\sketches
   \\EC26961FCABBA78A5928D7411C66733B
   \\sketch\\relative_include.ino.cpp"
-o 
"C:\\Users\\kenb4\\AppData\\Local\\arduino\\sketches
   \\EC26961FCABBA78A5928D7411C66733B
   \\sketch\\relative_include.ino.cpp.o"

You can compare files put in the sketch directory by checking that temp directory (<random>/sketch) after a build to see what actually got copied over.

Once you have done the mklink command, the file will appear as a normal file in the directory. For example

U:\arduino\project1>mklink xxx.h ..\include\xxx.h
symbolic link created for xxx.h <<===>> ..\include\xxx.h

U:\arduino\project1>dir
 Volume in drive U has no label.
 Volume Serial Number is CA18-63CF

 Directory of U:\arduino\project1

20/12/2025  09:52    <DIR>          .
20/12/2025  09:52    <DIR>          ..
20/12/2025  09:51                 4 project1.ino
20/12/2025  09:52    <SYMLINK>      xxx.h [..\include\xxx.h]
               2 File(s)              4 bytes
               2 Dir(s)  102,170,308,608 bytes free

U:\arduino\project1>

You can then compile your .ino file with #include "xxx.h". Like Linux, when you modify the .h file, the original in the include directory gets modified.

This is an incorrect conclusion. Your example shown that it is not the case:

The symlink includes a relative path.

The reason this still works is apparently because IDE, when copying your sketch to a separate location for building, copies all nested files and directories, dereferencing symlinks.