Using an ADA program in two or more OS's

In have a number of programs I want to use for instance as well under Windows 11 as in Linux. In the project file you have the possibility to read in which OS you are working, but in some cases that is not practical. For instance under windows I can create a link between an standard package I created and than link these with for instance the lines:

for Source_Dirs use ("..\..\Standaarden\Standaard Packages\Init\**",
                     "..\..\Standaarden\Standaard Packages\StackPointer\**",
                     "..\..\Standaarden\Standaard Packages\Pipe\**", 
                     "..\..\Standaarden\Standaard Packages\Buffer\**",
                     "..\..\Standaarden\Standaard Packages\Gtk_Message_Box\**");

I would like to use always:

for Source_Dirs use ("Init\**",
                     "StackPointer\**",
                     "Pipe\**", 
                     "Buffer\**",
                     "Gtk_Message_Box\**");

and use a path variable. it may be for instance the Path variable but that is so full of directions where to find something that an own path f.i. ADA_PACKAGES . My question can I somewhere find a way to make a project always look for that Path to find packages so that Source_Dir can always find the files. So how can the project file where these files are.

2 Likes

Here is an example of a project that builds for Linux, macOS, and Windows (extracted from https://github.com/pmunts/libsimpleio/blob/d03f21fffb81991105eeb55b6f22b3576605cd23/ada/programs/remoteio/default.gpr):

PROJECT Default IS
  LIBSIMPLEIO := external("LIBSIMPLEIO", "/usr/local/share/libsimpleio");

  FOR Source_Dirs USE (".",
    LIBSIMPLEIO & "/ada/bindings",
    LIBSIMPLEIO & "/ada/devices/**",
    LIBSIMPLEIO & "/ada/interfaces",
    LIBSIMPLEIO & "/ada/objects/**");

  FOR Object_Dir  USE "./obj";

  FOR Exec_Dir    USE ".";

  PACKAGE Compiler IS
    FOR Default_Switches ("Ada") USE
     ("-O3",
      "-ffunction-sections",
      "-fdata-sections",
      "-gnata",
      "-gnato1",
      "-gnatVa",
      "-gnatwa",
      "-gnatwJ",
      "-gnatwK",
      "-gnat2012"
     );
  END Compiler;

  -- Linker goop to find hidapi.dll or libhidapi.so

  OS      := external("OS", external("OSNAME", "unknown"));

  PACKAGE Linker IS
    CASE OS IS
      WHEN "Windows_NT" =>
        FOR Default_Switches ("ada") USE
          ("-L" & LIBSIMPLEIO & "/win64");

      WHEN "Darwin" =>
        FOR Default_Switches ("ada") USE
          ("-L/opt/homebrew/lib", "-ld_classic");

      WHEN OTHERS =>
        NULL;
    END CASE;
  END Linker;
END Default;

Everything is controlled by two environment variables: LIBSIMPLEIO and OS or OSNAME. LIBSIMPLEIO determines where the library packages necessary to build the program come from.

On Linux, the library packages are usually installed to /usr/local/share/libsimpleio/ada/ by a Debian or RPM package, in which case the default value for the Ada project variable is used and the eponymous environment variable is not necessary. If for some reason you don’t want to or can’t install the Debian or RPM package, you can clone https://github.com/pmunts/libsimpleio to some local directory and set LIBSIMPLEIO to point to the checkout e.g. add export LIBSIMPLEIO=$HOME/libsimpleio to .bashrc.

Since Remote I/O Protocol support for macOS and Windows was an afterthought to the Linux Simple I/O Library, there are no installation packages for macOS and Windows, so both macOS and Windows require the git checkout and LIBSIMPLEIO environment variable.

For my example, operating system idiosyncrasies manifested at link time rather than compile time and I used the OS environment variable to detect Windows and the OSNAME environment variable for all other operating systems. All of my Linux machines have OSNAME=debian13 added to /etc/environment and all of my macOS machines have export OSNAME=`uname` added to .bashrc and/or .zshrc.

Unfortunately, gprbuild provides no mechanism that I have found to do the equivalent of Unix `uname` inside the project file, which is sad because uname can provide all kinds of useful hardware target information.

1 Like

When using Alire, you can get the OS, the architecture and the distribution.

In the crate configuration Alire also generates a few built-in values to identify the host platform:

  • Alire_Host_OS

  • Alire_Host_Arch

  • Alire_Host_Distro

2 Likes

While needed are Target_OS and Target_Arch in the form of a project file.

This is how I handle this in Tada:

There are other parameters. E.g. the size of Stream_Element_Offset in capability of the atomic aspect. Some 32-bit targets have it 32-bit (which limits the maximal file size). Some have 64-bit. When implementing lock-free algorithms one needs to know if atomic would work on with Stream_Element_Offset. In GNAT it does, even when the machine has necessary instructions.

As I understand from the answers I got there is no solution for the question I have. It means that in all situations the project file must be changed to use it on another system. Besides that there could also changes needed in “Path” for the operating system. I normaly use Windows.

Is it an idea for future versions of the project file to add a possible line:

for Path use “Path name”; It than is possible that the project can choose the “Path” where to search for standard packages used in more than one program

AFAIR gprbuild understands / as a path separator, even on Windows.

1 Like

or make a mypaths.gpr





project mypaths is

  OS := external("OS", "win");

  case "OS" is
    when lin =>
  
       Init          := "../../Standaarden/Standaard Packages/Init/**"
       StackPointer  := "../../Standaarden/Standaard Packages/StackPointer/**";
       Pipe          := "../../Standaarden/Standaard Packages/Pipe/**";
       Buffer        := "../../Standaarden/Standaard Packages/Buffer/**";
       Gtk_Message_Box := "../../Standaarden/Standaard Packages/Gtk_Message_Box/**";
       
    when win =>
  
       Init          := "somewhere/else/Standaarden/Standaard Packages/Init/**"
       StackPointer  := "somewhere/else/Standaarden/Standaard Packages/StackPointer/**";
       Pipe          := "somewhere/else/Standaarden/Standaard Packages/Pipe/**";
       Buffer        := "somewhere/else/Standaarden/Standaard Packages/Buffer/**";
       Gtk_Message_Box := "somewhere/else/Standaarden/Standaard Packages/Gtk_Message_Box/**";

end mypaths;

                     

and use it in your original gpr


with "mypaths"


for Source_Dirs use (mypaths.Init & "/**",
                     mypaths.StackPointer & "/**",
                     mypaths.Pipe & "/**",
                     mypaths.Buffer & "/**",
                     mypaths.Gtk_Message_Box & "/**");
                     
                     

make sure to set an env-var “OS“ with the value “win“ or “lin”

or pick something else. Or look for a env-var present only in one of the platform and set a corresponding default value if it is missing

As mentioned in another post - ‘/’ in paths are ok in windows too - for gprbuild

1 Like