Why isn't my GNAT's standout file descript

2019-08-07 03:15发布

问题:

As part of a little project, I'm writing a shell in Ada. As such, when I was investigating the system calls, I learned that there are three ways to do it.

  1. The POSIX system calls, which are probably the least reliable.
  2. Passing the arguments along to C's system(), which I didn't really want to do, since this was about writing the emulator in Ada and not C.
  3. Using GNAT's runtime libraries.

I chose to go for the last option, considering this to be the most "Ada-like" of the choices. I found a code snippet on RosettaCode here. I copied and pasted it and compiled it after changing the "cmd.exe" to "ls" and removing the second argument definition. However, nothing happens when I run the executable. The shell just goes right back to the prompt. I have tested this on two different computers, one running Fedora 21, the other Debian Jessie. Here's what I've done to test it:

  • Seen if lacking an arguments string caused it
  • Checked if any of the file descriptors in GNAT's libraries are mis-named
  • Redirected both stderr and stdin to stdout just to see if GNAT was dumping them to the wrong FD anyway.
  • Looked thoroughly through the System.OS_lib library file, and there seems to be no reason.
  • Googled it, but GNAT's own page on the GCC website is very poorly documented.

For now I'm using the C.Interface system in the preparation of my shell, but I'm dissatisfied with this. I'm new to Ada and have only been tinkering with it for a month or so now, so if there's some kind of Ada wisdom here that would help I'm not in on it.

UPDATE: I have tried running it with absolute path, both to /usr/bin and /bin locations, and it doesn't work. Interestingly, the result code returned by the operating system is 1, but I don't know what that means. A quick search suggests that it's for "all general errors", and another site suggests that it's for "incorrect functions".

回答1:

I had to tweak the RosettaCode example a little to run /bin/ls on Debian Linux, but it does run as expected...

with Ada.Text_IO;     use Ada.Text_IO;
with Gnat.OS_Lib;   use Gnat.OS_Lib;

procedure Execute_Synchronously is
   Result    : Integer;
   Arguments : Argument_List :=
                 (  1=> new String'("-al")
                 );
begin
   Spawn
   (  Program_Name           => "/bin/ls",
      Args                   => Arguments,
      Output_File_Descriptor => Standout,
      Return_Code            => Result
   );
   for Index in Arguments'Range loop
      Free (Arguments (Index)); 
   end loop;
end Execute_Synchronously;

Changes :

  1. my Gnat (FSF Gnat 4.92 from Debian Jessie) warned about System.OS_Lib, recommending Gnat.OS_Lib instead. (Which simply renames System.OS_Lib .... why???
    System.OS_Lib comments:

-- Note: this package is in the System hierarchy so that it can be directly
-- be used by other predefined packages. User access to this package is via
-- a renaming of this package in GNAT.OS_Lib (file g-os_lib.ads).

  1. Program name including path.
  2. Arguments. The first time I ran it, it displayed the details of "ls" itself, because it was given its own name as the first argument, so I deleted that to see the current directory instead.

Notes :

  1. the best information ot the available subprograms and their arguments is usually in the package specs themselves in the "adainclude" folder : this is /usr/lib/gcc/x86_64-linux-gnu/4.9/adainclude on my Debian installation, locate system.ads will find yours. The specific files are: s-os_lib.ads for System.OS_Lib which exports Spawn and Standout, and a-textio.ads for Ada.Text_IO.
  2. Standout is not the preferred way of accessing Standard Output : it's a file descriptor (integer), the preferred way would be the Standard_Output function from Ada.Text_IO which returns a File. However there doesn't seem to be an overload for Spawn which takes a File (nor would I expect one in this low level library) so the lower level file descriptor is used here.


回答2:

Absent a shell, you'll need to search the PATH yourself or specify a full path for the desired executable:

Spawn (
   Program_Name => "/bin/ls",
   …
);

I have tried running it with absolute path…neither /usr/bin nor /bin locations work.

Use which to determine the full path to the executable:

$ which ls
/bin/ls


标签: shell ada gnat