Recent

Author Topic: [SOLVED] Problem running external program under Linux  (Read 9804 times)

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
[SOLVED] Problem running external program under Linux
« on: July 28, 2021, 11:48:28 pm »
Dear ALL,

I am struck with a strange problem when attempting to run an external program from a Lazarus GUI application under Linux.

I cannot distribute my real application at this time, but it is a relatively straightforward program which executes a C program, passing the name of text file as its only argument and counts the lines in the file; the program then enters a command loop where the user must type 'quit' in order to exit the program. Under Windows, the application works fine, but it fails under Linux. without issuing any error messages.

I am running Lazarus 1.8.2 under Lubuntu 18.04.5 LTS. I have installed Lazarus from the Ubuntu repositories, and therefore that is not the most recent version.

The only reasonable explanation I can find for this problem is that it may be related to that old version of Lazarus. However, before updating, I would like to be sure that it is really the problem. Could someone give it a try under a more recent version of Lazarus for Linux?

My sample code is attached. I hope that perusal of the code will make the problem easier to understand.

Thanks in advance!

With best wishes,
« Last Edit: July 30, 2021, 12:52:34 am by maurobio »
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

rsz

  • New Member
  • *
  • Posts: 45
Re: Problem running external program under Linux
« Reply #1 on: July 29, 2021, 03:52:44 am »
Hi,

I don't have a windows machine to compare to right now but I believe the issue you are experiencing is due to how Linux handles console applications differently than Windows. I assume you expect a command prompt to be opened on Linux when the counter program is run?

On Linux you must execute a terminal emulator explicitly (such as xterm) and then pass it arguments to execute your counter program rather than launching the counter program directly.

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1024
Re: Problem running external program under Linux
« Reply #2 on: July 29, 2021, 06:52:12 am »
hello,
have you tried to launch your compiled program in a xterm ? if you launch your program in the IDE , display the console In/out window ->  View/Debug Windows/Console In/Output  may be View/Debug Windows/Console Terminal in your Lazarus version.
Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Problem running external program under Linux
« Reply #3 on: July 29, 2021, 07:26:39 am »
The C program seems to always return exit code 0; in *nix you should instead (or also) check ExitStatus, which will tell you if there was some problem running the program irrespective of what the program itself returns as ExitCode.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
Re: Problem running external program under Linux
« Reply #4 on: July 29, 2021, 01:12:59 pm »
Dear ALL,

Thank you very much indeed for your replies. However, I am still at a loss. I could not fully understand the issue with 'xterm'. But as far as I can see, a console program cannot be executed from a GUI application under Linux in the same way it can be under Windows.

How do I 'execute a terminal emulator explicitly', as suggested by @rsz? Could an example be provided? Also, I would appreciate a tip on how to check ExitStatus as suggested by @lucamar. Unfortunately, none of the explanations provided in the links below mention GUI applications:

https://wiki.freepascal.org/Executing_External_Programs#Using_fdisk_with_sudo_on_Linux
https://forum.lazarus.freepascal.org/index.php?topic=10462.0

I attach a slightly updated version of my sample code, now including a 'runcounter.pas' program as a console-mode application, which works fine under both Linux and Windows.

Thanks again for your time and patience!

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Problem running external program under Linux
« Reply #5 on: July 29, 2021, 02:44:49 pm »
But as far as I can see, a console program cannot be executed from a GUI application under Linux in the same way it can be under Windows.

It can, only Linux doesn't need a "command prompt" or a console window to execute it, which is why if you want that you have to run the program under a terminal emulator. That is, you "run" the terminal and pass to it, as parameters, the program you want it to execute.

Quote
How do I 'execute a terminal emulator explicitly', as suggested by @rsz? Could an example be provided?

Basically, like this (just Q&D example, mind!):
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses
  6.   Process;;
  7.  
  8. var
  9.   AProcess: TProcess;
  10.  
  11. begin
  12.   AProcess := TProcess.Create(Nil);
  13.   try
  14.     AProcess.Executable := DetectXTerm;
  15.     AProcess.Parameters.Add('counter');
  16.     AProcess.Parameters.Add('lines.txt');
  17.     AProcess.Options := AProcess.Options + [poWaitOnExit];
  18.     AProcess.Execute;
  19.   finally
  20.     AProcess.Free;
  21.   end;
  22. end.

Quote
Also, I would appreciate a tip on how to check ExitStatus as suggested by @lucamar.

Well, you have to know the possible codes to diagnose the problem but at a basic level you check against zero, as you do with ExitCode, and "barf" out if it failed.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

sstvmaster

  • Sr. Member
  • ****
  • Posts: 258
Re: Problem running external program under Linux
« Reply #6 on: July 29, 2021, 02:53:34 pm »
... but it is a relatively straightforward program which executes a C program, passing the name of text file as its only argument and counts the lines in the file ...

Why don't you count the lines from this file youself?
Windows 10 (64 bit)
Lazarus: 2.0.12 / Trunk x32

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
Re: Problem running external program under Linux
« Reply #7 on: July 29, 2021, 03:31:16 pm »
@lucamar,

Unfortunately, it still didn't work. DetectXTerm returns 'x-terminal-emulator', which bash claims does not exist on my system (shouldn't it return LXTerminal, since I am running Lubuntu?). My program just stalls as before.

@sstvmaster.

To count lines in a file is not really my problem; the 'counter' program is just a dummy sample program which emulates the behaviour of the 'true' program I am attempting to run from my GUI (that is, a console program which reads a file passed as argument and waits for user commands until a 'quit' command is typed).

Again, thank you!

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

MarkMLl

  • Hero Member
  • *****
  • Posts: 3030
Re: Problem running external program under Linux
« Reply #8 on: July 29, 2021, 03:46:23 pm »
It can, only Linux doesn't need a "command prompt" or a console window to execute it, which is why if you want that you have to run the program under a terminal emulator. That is, you "run" the terminal and pass to it, as parameters, the program you want it to execute.

It will probably never need a window (i.e. xterm or equivalent) to run a child program, unless that program requires that the DISPLAY or one of the XDG_ shell variables etc. to be set up sensibly. I know that sounds silly for a command line program, but consider the case of the Subversion client or Sudo which can tell the desktop environment to display a prettified password prompt dialog(ue).

It might need a shell if, for some reason, the command being passed includes redirection/piping or variable substitution etc., there's usually ways of working round this.

If termination is failing, it is likely to be because the parent is not waiting for activity to stop, or because the child is expecting something like \r\n and is only seeing \r.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

avra

  • Hero Member
  • *****
  • Posts: 2226
    • Additional info
Re: Problem running external program under Linux
« Reply #9 on: July 29, 2021, 03:56:26 pm »
Maybe it could help to take a look at https://bitbucket.org/avra/ct4laz. That is a GUI application which executes 7zip command line executable with parameters and processes it's output, while working on both Windows and Linux.
ct2laz - Conversion between Lazarus and CodeTyphon
bithelpers - Bit manipulation for standard types
pasettimino - Siemens S7 PLC lib

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
Re: Problem running external program under Linux
« Reply #10 on: July 29, 2021, 04:32:17 pm »
@Avra,

Thanks a lot. But ct4laz seems to be a large collection of components, and I cannot install it at this time. Could you please point out a specific example out that collection, which I could take a look at?

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

MarkMLl

  • Hero Member
  • *****
  • Posts: 3030
Re: Problem running external program under Linux
« Reply #11 on: July 29, 2021, 04:51:58 pm »
This is something I've used in the past. I'm not saying it's good code and the actual child program name etc. is set up in a separate form, but I /am/ saying it works with a fair number of child programs (typically, an APL interpreter that requires something like )bye\r to terminate).

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.MenuConnectionConnectProgramClick(Sender: TObject);
  2.  
  3. var     process: TProcess= nil;
  4.         i: integer;
  5.  
  6.  
  7.   procedure shutdown(const msg: string= '');
  8.  
  9.   begin
  10.     if msg <> '' then begin
  11.       ConnectProgressForm.Label1.Caption := msg;
  12.       if StatusBar1.SimplePanel = true then     (* Won't mess up status bar     *)
  13.         FullWidth(msg)
  14.     end;
  15.     if process <> nil then
  16.       try
  17.         process.Terminate(0)
  18.       except
  19.       end;
  20.     FreeAndNil(process)
  21.   end { shutdown } ;
  22.  
  23.  
  24.   procedure unableToConnect(const server: string);
  25.  
  26.   begin
  27.   {$ifdef SMARTPOS }
  28.     MessageDlgPos('Unable to connect ' + server, mtError, [mbOK], 0,
  29.           (Left + Width div 2 + Screen.Width div 2) div 2,
  30.           (Top + Height div 2 + Screen.Height div 2) div 2)
  31.   {$else           }
  32.     MessageDlg('Unable to connect ' + server, mtError, [mbOK], 0)
  33.   {$endif SMARTPOS }
  34.   end { unableToConnect } ;
  35.  
  36.  
  37.   (* If the second parameter is false trim and return the first parameter.
  38.     Otherwise locate substrings that look like shell environment names and
  39.     expand them.
  40.   *)
  41.   function expand(const str: string; doExpand: boolean): string;
  42.  
  43.   var   unprocessed, name: string;
  44.  
  45.   begin
  46.     result := Trim(str);
  47.     if doExpand then begin
  48.       unprocessed := result;
  49.       result := '';
  50.       while unprocessed <> '' do begin
  51.         case unprocessed[1] of
  52.           '~': begin
  53.                  if result = '' then            (* At start only                *)
  54.                    result := UserHomeDirectory
  55.                  else
  56.                    result += '~';
  57.                  Delete(unprocessed, 1, 1)
  58.                end;
  59.           '\': begin
  60.                  Delete(unprocessed, 1, 1);     (* Backslash                    *)
  61.                  if unprocessed <> '' then begin
  62.                    result += unprocessed[1];    (* Might be special, don't care *)
  63.                    Delete(unprocessed, 1, 1)
  64.                  end
  65.                end;
  66.           '$': begin                    (* No provision here for \{ or \}       *)
  67.                  Delete(unprocessed, 1, 1);     (* Dollar                       *)
  68.                  name := '';
  69.                  if unprocessed <> '' then begin
  70.                    if unprocessed[1] <> '{' then
  71.                      while (unprocessed <> '') and
  72.                         (unprocessed[1] in ['0'..'9', 'A'..'Z', 'a'..'z', '_']) do begin
  73.                        name += unprocessed[1];
  74.                        Delete(unprocessed, 1, 1)
  75.                      end
  76.                    else begin
  77.                      Delete(unprocessed, 1, 1); (* Left brace                   *)
  78.                      while (unprocessed <> '') and (unprocessed[1] <> '}') do begin
  79.                        name += unprocessed[1];
  80.                        Delete(unprocessed, 1, 1)
  81.                      end;
  82.                      Delete(unprocessed, 1, 1)  (* Right brace                  *)
  83.                    end;
  84.                    if name <> '' then
  85.                      result += GetEnvironmentVariable(name)
  86.                  end
  87.                end
  88.         otherwise
  89.           result += unprocessed[1];
  90.           Delete(unprocessed, 1, 1)
  91.         end
  92.       end
  93.     end
  94.   end { expand } ;
  95.  
  96.  
  97. begin
  98.   if CurrentConnectionType() <> ConnectionNone then begin
  99.     unableToConnect('since already online');
  100.     exit
  101.   end;
  102.   process := TProcess.Create(nil);
  103.  
  104. (* If we're not here via a reconnect then display a form for extra program      *)
  105. (* parameters. Even if we know there's no extra parameters we have to set this  *)
  106. (* form up since its content is used as the command line (ouch)-:               *)
  107.  
  108.   if not (Reconnecting in ConnectionFlags) then
  109.     if ProgramSettingsForm.CheckBoxParameters.Checked then
  110.       try
  111.         case ProgramConnectForm.ShowModal of
  112.           mrOk: begin
  113.                 end
  114.         otherwise
  115.           ProgramConnectForm.FormShow(nil);     (* Check program path           *)
  116.           FreeAndNil(process);
  117.           exit
  118.         end
  119.       finally
  120.       end                               (* End of fresh or reconnect setup      *)
  121.     else
  122.       ProgramConnectForm.FormShow(nil);
  123.  
  124. (* We should have a good program name etc.                                      *)
  125.  
  126.   if FileExists(ProgramConnectForm.Executable) then begin
  127.     process.Executable := ProgramConnectForm.Executable;
  128.     for i := 0 to ProgramSettingsForm.MemoOptions.Lines.Count - 1 do
  129.       if Trim(ProgramSettingsForm.MemoOptions.Lines[i]) <> '' then
  130.         process.Parameters.Add(Trim(ProgramSettingsForm.MemoOptions.Lines[i]));
  131.     for i := 0 to ProgramConnectForm.MemoParameters.Lines.Count - 1 do
  132.       if Trim(ProgramConnectForm.MemoParameters.Lines[i]) <> '' then
  133.         process.Parameters.Add(Trim(ProgramConnectForm.MemoParameters.Lines[i]));
  134.     if ProgramSettingsForm.CheckBoxEnvironmentInherit.Checked then
  135.       for i := 1 to GetEnvironmentVariableCount do
  136.         process.Environment.Add(GetEnvironmentString(i));
  137.     for i := 0 to ProgramSettingsForm.MemoEnvironment.Lines.Count - 1 do
  138.       if expand(ProgramSettingsForm.MemoEnvironment.Lines[i],
  139.                                 ProgramSettingsForm.CheckBoxEnvironmentExpand.Checked) <> '' then
  140.         process.Environment.Add(expand(ProgramSettingsForm.MemoEnvironment.Lines[i],
  141.                                 ProgramSettingsForm.CheckBoxEnvironmentExpand.Checked));
  142.     if Trim(ProgramSettingsForm.LabeledEditWorkingDirectory.Text) <> '' then
  143.       process.CurrentDirectory := ProgramSettingsForm.LabeledEditWorkingDirectory.Text;
  144.     process.Options := [poUsePipes];
  145.     process.Execute;
  146.     Sleep(100);
  147.     Application.ProcessMessages;
  148.     if process.Running then
  149.       StatusBar1.Panels[DbgOnline].Text := 'Online'
  150.     else
  151.       shutdown;
  152.     LastConnectionType := ConnectionProgram
  153.   end else
  154.     shutdown;
  155.   if process = nil then
  156.     exit;
  157.  
  158. (* Assume that we've exited before getting here if things aren't OK.            *)
  159.  
  160.   ProcessObject := process;             (* Global record that the port is open  *)
  161.   MenuConnectionConnectUsingProfile.Enabled := false;
  162.   MenuConnectionConnectToLine.Enabled := false;
  163.   MenuConnectionReconnect.Enabled := false;
  164.   MenuConfigurationRJEAttachListingDisplay.Enabled := false;
  165.   MenuConfigurationRJEAttachPunchEditor.Enabled := false;
  166.   MenuConnectionAttention.Enabled := true;
  167.   MenuConnectionBreak.Enabled := SerialClientHandle <> -1;
  168.   MenuConnectionDisconnect.Enabled := true;
  169.   MenuConnectionRestartRJE.Enabled := false
  170. end { TMainForm.MenuConnectionConnectProgramClick } ;
  171.  

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
Re: Problem running external program under Linux
« Reply #12 on: July 29, 2021, 04:56:03 pm »
Dear ALL,

Just in an attempt to clarify my problem, I attach two screenshots of my sample application running under MS-Windows. The first shows the application's main form, and the second shows the counter program in a console window (displaying the number of lines in the file passed as argument and then waiting for user input).

Hope this helps.

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

maurobio

  • Sr. Member
  • ****
  • Posts: 255
  • Ecology is everything.
    • GitHub
Re: Problem running external program under Linux
« Reply #13 on: July 29, 2021, 05:00:57 pm »
@MarkMLI,

Thanks for your code, but is all that really necessary just for executing a program in console mode from a GUI application?  :o

Frankly, it is disappointing and disturbing to be able to do that so easily under MS-Windows but not under Linux (where it should be even simpler and better!).

With best wishes,
UCSD Pascal / Burroughs 6700 / Master Control Program
Lazarus 1.8.2/2.0.8 - FPC 3.0.4 on GNU/Linux Mint 19, GNU/Linux Lubuntu 18.04, Windows XP SP3, Windows 7 Professional, Windows 10 Home

MarkMLl

  • Hero Member
  • *****
  • Posts: 3030
Re: Problem running external program under Linux
« Reply #14 on: July 29, 2021, 05:01:34 pm »
Hope this helps.

Not in the least to be frank, since even if the child program has identical source compiling it for Linux will use different low-level libraries and API calls.

MarkMLl
Turbo Pascal v1 on CCP/M-86, multitasking with LAN and graphics in 128Kb.
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018