在Ada中如何调用外部程序?

在Ada中如何调用外部程序?,ada,gnat,Ada,Gnat,如何从Ada程序文本中调用外部命令(就像我在unixshell或Windows命令提示符下键入命令一样) 我更喜欢非特定于蚊虫的解决方案,但无论如何,我会将我自己的发现作为初始答案发布。with gnat.OS_Lib; 主要程序是 退出代码:整数; 开始 退出代码:=GNAT.OS_Lib.Spawn(程序名=>“mv”,参数=>(新字符串'(“README.md”),新字符串'(“README.txt”); 如果退出_Code/=0,则 使用“退出代码”引发程序错误:&退出代码图像; 如果结

如何从Ada程序文本中调用外部命令(就像我在unixshell或Windows命令提示符下键入命令一样)

我更喜欢非特定于蚊虫的解决方案,但无论如何,我会将我自己的发现作为初始答案发布。

with gnat.OS_Lib;
主要程序是
退出代码:整数;
开始
退出代码:=GNAT.OS_Lib.Spawn(程序名=>“mv”,参数=>(新字符串'(“README.md”),新字符串'(“README.txt”);
如果退出_Code/=0,则
使用“退出代码”引发程序错误:&退出代码图像;
如果结束;
端干管;
如果您在windows上,请将“mv”更改为“move”


有关非阻塞和/或捕获stdout/stderr的信息,请参阅扩展此功能。

您也可以使用
系统。支持于,例如

  • Linux()
  • 窗口()
请注意,错误会写入标准错误

main.adb

with Ada.Text_IO;
with Interfaces.C;

procedure Main is

   package C renames Interfaces.C;
   use type C.int;
   
   function system (command : C.char_array) return C.int
     with Import, Convention => C;

   command : aliased constant C.char_array :=
     C.To_C ("mv README.md README.txt");

   result : C.int;

begin
   result := system (command);
   if result = 0 then
      Ada.Text_IO.Put_Line ("OK");
   else
      Ada.Text_IO.Put_Line ("Failed");
   end if;
end Main;
with Ada.Text_IO; use Ada.Text_IO;
with POSIX;       use POSIX;

with POSIX.Process_Primitives;
with POSIX.Process_Identification;

procedure Main is
   
   package PP renames POSIX.Process_Primitives;
   package PI renames POSIX.Process_Identification;
   
   Filename : constant POSIX_String := "sleep";
   Args     : POSIX_String_List;  
   
   PID : PI.Process_ID;
   PT  : PP.Process_Template;   
   PS  : PP.Termination_Status;
   
begin
   Append (Args, Filename);   --  argv[0]
   Append (Args, "5");        --  argv[1]

   PP.Open_Template (PT);
   
   PP.Start_Process_Search
     (Child    => PID,
      Filename => Filename,
      Template => PT,
      Arg_List => Args);

   loop
      Put_Line ("Waiting...");
      
      PP.Wait_For_Child_Process
        (Status => PS,
         Child  => PID,
         Block  => False);
      
      exit when PP.Status_Available (PS);
      delay 1.0;
   end loop;
   
   Put_Line ("The child terminated with status code: "
               & PP.Exit_Status_Of (PS)'Image);
   
   PP.Close_Template (PT);   
end Main;

基于我对花店图书馆的评论(参见),我添加了另一个例子(仅供参考和参考,而不是作为对原始问题的严肃回答)。不幸的是,我在评论中提到的Florist版本没有根据GNAT的最新版本(例如GNAT CE 2020)进行编译。这个版本的库似乎在某种程度上依赖于GNAT的内部结构,而GNAT的内部结构经过了轻微的修改(因此库不再像最初预期的那样独立于编译器)。尽管如此,为了完整性,如果您能够编译它(使用较旧版本的GNAT或修复源代码),那么下面的示例将在不阻塞的情况下生成一个子进程,并等待它完成

main.adb

with Ada.Text_IO;
with Interfaces.C;

procedure Main is

   package C renames Interfaces.C;
   use type C.int;
   
   function system (command : C.char_array) return C.int
     with Import, Convention => C;

   command : aliased constant C.char_array :=
     C.To_C ("mv README.md README.txt");

   result : C.int;

begin
   result := system (command);
   if result = 0 then
      Ada.Text_IO.Put_Line ("OK");
   else
      Ada.Text_IO.Put_Line ("Failed");
   end if;
end Main;
with Ada.Text_IO; use Ada.Text_IO;
with POSIX;       use POSIX;

with POSIX.Process_Primitives;
with POSIX.Process_Identification;

procedure Main is
   
   package PP renames POSIX.Process_Primitives;
   package PI renames POSIX.Process_Identification;
   
   Filename : constant POSIX_String := "sleep";
   Args     : POSIX_String_List;  
   
   PID : PI.Process_ID;
   PT  : PP.Process_Template;   
   PS  : PP.Termination_Status;
   
begin
   Append (Args, Filename);   --  argv[0]
   Append (Args, "5");        --  argv[1]

   PP.Open_Template (PT);
   
   PP.Start_Process_Search
     (Child    => PID,
      Filename => Filename,
      Template => PT,
      Arg_List => Args);

   loop
      Put_Line ("Waiting...");
      
      PP.Wait_For_Child_Process
        (Status => PS,
         Child  => PID,
         Block  => False);
      
      exit when PP.Status_Available (PS);
      delay 1.0;
   end loop;
   
   Put_Line ("The child terminated with status code: "
               & PP.Exit_Status_Of (PS)'Image);
   
   PP.Close_Template (PT);   
end Main;
输出

$./obj/main
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
Waiting...
The child terminated with status code:  0

我们有一个很好的带有异步通知的流程API。看一看。它可以在Linux、Windows和Mac OS X上工作。可以选择与Glib事件循环集成

   Args : Spawn.String_Vectors.UTF_8_String_Vector;
   L    : aliased Listeners.Listener;
begin
   Args.Append ("Hello World");
   P.Set_Program ("/bin/echo");
   P.Set_Arguments (Args);
   P.Set_Working_Directory ("/tmp");
   P.Set_Listener (L'Unchecked_Access);
   P.Start;

对于非阻塞系统调用,您将如何执行此操作?我惊讶地发现GNAT.OS_Lib.Spawn没有在引擎盖下调用系统。它称为“u_gnat_portable_spawn”,非阻塞的_spawn也会这样做;同样,这是因为我正在寻找一些东西来取代GNAT运行时特定的“\uuu GNAT\u portable\u no\u block\u spawn”,这样代码将使用任何Ada编译器进行编译。@TamaMcGlinn如果您不想在
OS_Lib
中使用GNAT特定的抽象,那么恐怕您将不得不使用OS特定的C系统调用,最有可能的是
使用的那些会产生
(参见示例)。Ada本身(即标准库)不知道进程的概念。@TamaMcGlinn对于与POSIX兼容的操作系统的交互(例如启动进程等),在某个时间点,有一个POSIX Ada语言接口可用(请参阅和Wiki页)以及一个名为(有关流程原语,请参见
posix-process\u primitives.ads
)。但是,这个库似乎有些不推荐使用。