Oberon RTK

Module Search Path

Finding imported modules.

Introduction

From the Astrobe docs:

The editor, compiler, linker and builder first search the current folder when trying to locate imported source code, symbol and object files. They then search each of the folders listed in the current configuration's Library Pathnames textbox. The search continues until the file is found or the last folder in the list has been searched.

The library search path[1] can be specified using

  • absolute directory path names, or
  • relative directory path names.

The search in the library path goes from top to bottom, in the order as specified in Astrobe's config files.

About the 'current folder':

The 'current folder' is the folder which contains the source code of the target of the operation. When linking and building the target is the module which imports Main. When compiling a module, the 'current folder' is the folder which contains the source code of the module being compiled.

The build system performs a series of separate compilations, each for one module in the system as needed, in the correct order, hence the 'current folder' is being dynamically determined for each module during the build process.

Absolute Directory Path Names

For example:

C:\Astrobe\RP2040\Lib\PiPico
C:\Astrobe\RP2040\Lib\General

We can use a variable, such as %AstrobeRP2040% = C:\Astrobe\RP2040:

%AstrobeRP2040%\Lib\PiPico
%AstrobeRP2040%\Lib\General

Absolute directory path names are as straight-forward as it gets. There's no dynamic resolution of these path names when the compiler or linker runs (see 'current folder' above, though).

Relative Directory Path Names

With a project structure like this (expanding the above example):

+ C:\Astrobe\
  + RP2040
    + Lib
      + PiPico
      + General
    + Progs
      + prog0
        + Prog0.mod (imports M0 and modules in Lib)
        + M0.mod
      + prog1
        + Prog1.mod (imports M1 and modules in Lib)
        + M1.mod

we could use this search path:

..\Lib\General
..\..\Lib\PiPico
..\..\Lib\General

The rules are:

During compilation, relative paths are relative to the folder which contains the module being compiled.

During the linking phase, relative paths are relative to the folder which contains the module (which imports Main) being linked.

Note that the linker (and the build system) must be able to find all modules via relative directory paths from the program directory, even if these locations are not strictly required for the compiler.

When we build Prog0.mod:

  • M0.mod is found via the 'current folder' rule;
  • the modules in Lib imported in Prog0.mod and M0.mod are found via ..\..\Lib\PiPico and ..\..\Lib\General, since the relative directory path names are resolved with respect to prog0;
  • the modules imported in any module in Lib\PiPico from Lib\General are found via ..\Lib\General (there are no imports vice versa);
  • all imports within Lib\PiPico and Lib\General are found via the 'current folder' rule.

However, note that ..\..\Lib\PiPico and ..\..\Lib\General are also resolved and applied for all modules in Lib\PiPico and Lib\General, ie. the actual search path "reaches" into directory Astrobe, which may or may not be a problem, depending on any directory names and contents there.

If we take a more complex project directory structure, for example if we have sub-directories for sub-systems, and a sub-directory for general modules:

+ C:\Astrobe\
  + RP2040
    + Lib
      + PiPico
      + General
    + Progs
      + prog0
        + Prog0.mod
        + general
          + G0.mod
          + ...
        + sub-system0
          + S0.mod
          + ...
        + sub-system1
          + S1.mod
          + ...
      + prog1
        + Prog1.mod
        + M1.mod

A possible corresponding search path could be:

sub-system0 (find prog0\sub-system0 from prog0)
sub-system1 (find prog0\sub-system1 from prog0)
general (find prog0\general from prog0)
..\general (find general from sub-systems)
..\..\Lib\PiPico (find Lib\PiPico from prog0)
..\..\Lib\General (find Lib\General from prog0))
..\..\..\Lib\PiPico (find Lib\PiPico from prog0\general etc.)
..\..\..\Lib\General (find Lib\General from prog0\general etc.)
..\Lib\General (find Lib\General from Lib\PiPico)

Again, all relative directory paths are resolved and applied for all modules, including in Lib, and with the "triple parent" ..\..\..\ we're now reaching into C:\, and the "downwards" references such as general and sub-system0 extend the actual search path too, for example, prog0\sub-system0\general, or Lib\General\general, for the modules located there.

Now introduce your own re-usable library, for example:

+ C:\Astrobe\
  + RP2040
    + Lib
      + PiPico
      + General
    + CustomLib
      + pico
      + pico-w
      + gps (making stuff up here...:) 
      + sonar
      + ...
      + general
    + Progs
      + prog0
        + Prog0.mod
        + general
          + G0.mod
          + ...
        + sub-system0
          + S0.mod
          + ...
        + sub-system1
          + S1.mod
          + ...
      + prog1
        + Prog1.mod
        + M1.mod

And you see were this leads.

Astrobe handles non-existing directories in the search path gracefully by ignoring them. Hence, we don't get any tool error here. But the number of required defined relative search path segments, and the "explosion" of the actual search path show that the above approach is most likely not to be recommended.

Hybrid

We could use a hybrid solution based on absolute and relative directory paths. I honestly have not thoroughly thought this through yet in each and every detail, but I doubt it will change the following recommendation.

See Library Customisation for a simple example of a generic, hybrid search path.

Conclusion and Recommendation

With the current concept and implementation for relative directory paths,[2] I recommend using absolute directory path names other than for simple structures and set-ups. They are straight-forward and easy to understand, without any potential issues with expanding the actual search path in unintended ways.

For the last example, above:[3]

%Astrobe2040%\Progs\prog0\sub-system0
%Astrobe2040%\Progs\prog0\sub-system1
%Astrobe2040%\Progs\prog0\general
%Astrobe2040%\Progs\prog0
%Astrobe2040%\CustomLib\gps
%Astrobe2040%\CustomLib\sonar
%Astrobe2040%\CustomLib\pico-w
%Astrobe2040%\CustomLib\pico
%Astrobe2040%\CustomLib\general
%Astrobe2040%\Lib\PiPico
%Astrobe2040%\Lib\General

Or, with project and custom library directories outside %Astrobe2040%:[4]

C:\Projects\Oberon\Progs\prog0\sub-system0
C:\Projects\Oberon\Progs\prog0\sub-system1
C:\Projects\Oberon\Progs\prog0\general
C:\Projects\Oberon\Progs\prog0
C:\Oberon\Libs\CustomLib\gps
C:\Oberon\Libs\CustomLib\sonar
C:\Oberon\Libs\CustomLib\pico-w
C:\Oberon\Libs\CustomLib\pico
C:\Oberon\Libs\CustomLib\general
%Astrobe2040%\Lib\PiPico
%Astrobe2040%\Lib\General

Obviously, this search path is not generic, ie. it is project-dependent, since we have to use the name of the project directory. But any non-trivial project requires this anyway.


  1. I am following the Unix terminology: there is one search path, consisting of zero or more directory paths, each indicating a location where to look for imported modules. ↩︎

  2. Since each and every module must be found by the linker anyway via relative directory paths "dowwards" from the main program's directory, I believe all modules should only and exactly be given these "downwards" search directories for compilation (plus their current directory), and not require the "upwards" paths. That is, the modules get the same search path as the linker (and the build system). ↩︎

  3. This search path also includes possible imports that are not included in the version with relative directory paths above, for example between sub-systems. ↩︎

  4. The Astrobe search path variables can be set to any value. ↩︎

Last updated: 3 June 2025