你如何在 Ada 中调用外部程序?
How do you call an external program in Ada?
如何从 Ada 程序文本中调用外部命令(就像我在 Unix shell 或 Windows 命令提示符下输入的一样)?
我更喜欢非特定于 gnat 的解决方案,但无论如何我都会 post 我自己找到的作为初始答案。
with GNAT.OS_Lib;
procedure main is
Exit_Code : Integer;
begin
Exit_Code := GNAT.OS_Lib.Spawn (Program_Name => "mv", Args => (new String'("README.md"), new String'("README.txt")));
if Exit_Code /= 0 then
raise Program_Error with "Exit code:" & Exit_Code'Image;
end if;
end main;
如果您在 windows,请将 'mv' 更改为 'move'。
请参阅 the GNAT.OS_Lib documentation 以将其扩展为非阻塞 and/or 捕获 stdout/stderr。
您也可以使用 system
。支持
请注意,错误会写入标准错误。
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;
根据我对 Florist 库的评论(参见 ),我添加了另一个示例(仅供参考和信息,不是对原始问题的认真回答)。不幸的是,我在评论中提到的 Florist 版本无法在最新版本的 GNAT(例如 GNAT CE 2020)上编译。这个版本的库似乎在某种程度上依赖于 GNAT 的内部结构,这些内部结构经过了轻微的修改(因此该库不再像最初预期的那样独立于编译器)。尽管如此,为了完整起见,如果您能够编译它(使用旧版本的 GNAT 或通过修复源代码),那么下面的示例将在不阻塞的情况下生成一个子进程并等待它完成。
main.adb
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,带有异步通知。看看an example。它适用于 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;
如何从 Ada 程序文本中调用外部命令(就像我在 Unix shell 或 Windows 命令提示符下输入的一样)?
我更喜欢非特定于 gnat 的解决方案,但无论如何我都会 post 我自己找到的作为初始答案。
with GNAT.OS_Lib;
procedure main is
Exit_Code : Integer;
begin
Exit_Code := GNAT.OS_Lib.Spawn (Program_Name => "mv", Args => (new String'("README.md"), new String'("README.txt")));
if Exit_Code /= 0 then
raise Program_Error with "Exit code:" & Exit_Code'Image;
end if;
end main;
如果您在 windows,请将 'mv' 更改为 'move'。
请参阅 the GNAT.OS_Lib documentation 以将其扩展为非阻塞 and/or 捕获 stdout/stderr。
您也可以使用 system
。支持
请注意,错误会写入标准错误。
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;
根据我对 Florist 库的评论(参见
main.adb
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,带有异步通知。看看an example。它适用于 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;