‘Exit code’ (as vezes chamado de ‘exit status’) é um código numérico deixado pelo programa assim que é encerrado. O padrão posix seja no ambiente windows ou unices-like como linux e bsd esperam que um ‘exit code’ igual a zero signifique que o programa terminou sem nenhuma anormalidade e com isso o sistema operacional e/ou programas subsequentes poderão prosseguir em conformidade. No entanto, um valor diferente de zero indicará um alerta(warning) ou um erro fatal(fatal errror). Programadores para Windows geralmente usam ‘exit code’ com entre 1…255 para indicar tanto erros fatais(fatal errors) como também alertas(warnings). Programadores mais experientes, sempre que cabível preferem usar os ‘exit code’ comuns do terminal como cmd.exe no Windows ou bash no Linux já usam alguns códigos, por exemplo:
- Invalid function number
- File not found
- Path not found
- Too many open files
- Access denied
- Invalid handle.
- Memory control blocks destroyed
- Insufficient memory
- Invalid memory block address
- Invalid environment
- Invalid format
- Invalid access code
- (…)
Meu costume, quando um arquivo que é necessário para minha aplicação prosseguir não é encontrado então encerro o programa com ‘exit code’ igual à ‘2’ que para o MS-DOS/CMD do Windows equivale a ‘File not found’. Programadores experientes com Windows estão acostumados com esse código. Para todas as outras coisas que não há um padrão definido, criamos um código numérico arbitrário e se este alguém é um bom programador documentou isso em algum lugar.
Stdout e Stderr são dispositivos de saída. Stdout é basicamente a interface de tela/terminal do computador, quando um texto é enviado para lá, na verdade o texto esta indo para a tela/terminal do computador. Stderr é basicamente a mesma coisa diferenciando-se pelo seguinte, todo texto enviado para stderr é identificado como um erro de sistema e geralmente há um serviço que monitora tais colocando-os em arquivos de log para serem vistos mais tarde ou disparar algum evento.
Na minha experiência como consultor e analisando muito programas de terceiros chego a conclusão que é raro qualquer ‘exit code’ ou uso de stdout/stderr em programas desktops, mas utilizado com mais frequência em programas de backend. Em desktops, por alguma razão os programadores preferem usar mecanismos próprios de log e será com eles que os mesmos farão diagnóstico se houver problema.
Agendadores de tarefas ou scripts de backup(dentre outras funcionalidades de scripts) são os que mais tiram proveito de stdout/stderr e ‘exit code’. Por exemplo, Linux ou Windows possuem excelentes agendadores de tarefas que se aproveitam do ‘exit code’ para compreender se uma tarefa obteve êxito ou falhou. Quando percebe a ‘falha’ então as mensagens exibidas durante a execução (stdout/stderr) podem ser empacotadas e então enviada por email a alguém responsável. É assim que um script, serviço ou integração com outros programas devem funcionar.
Usando o FreePascal um jeito de enviar uma mensagem ao stdout/stderr é usando o comando WriteLn(dispositivo , mensagem) onde o dispositivo pode ser stderr ou stdout. Veja este exemplo onde no OnShow do form testamos a existência dum arquivo de configuração e caso não exista então envio uma mensagem ao stderr e o programa prossegue:
if not FileExists('configure.ini') then
begin
writeln(stderr,'Arquivo "configure.ini" não encontrado.');
end;
No exemplo abaixo é basicamente a mesma coisa, mas o programa não irá prosseguir, será terminado com ‘exit code’ igual a 2:
if not FileExists('configure.ini') then
begin
writeln(stderr,'Arquivo "configure.ini" não encontrado.');
Sleep(5000); // 5s de espera
Halt(2); // <-- Exit Code 2
end;
Esse tipo de esmero dentro de um programa é muito bem vindo e ajuda a integrar seu programa com outros. Mas como percebê-los quando estiver executando um programa com interface gráfica (GUI), visto que stdout/stderr apenas são vistos em terminais?
Você pode rodar seu programa diretamente do terminal ou desabilitar essa opção aqui em Project|Options|Compiler Options|Config and Target e desabilitar a opção Win32 gui application (-WG) :
A opção Win32 gui application (-WG) desmarcada permite exibir um terminal enquanto a GUI é executada, daí então qualquer mensagem enviada para stdout/stderr será exibida:
Mas há um problema, quando o programa termina, o terminal atrás dele será fechado também e por isso não dará para ver o ‘exit code’ . Para ver o ‘exit code’ quando o programa é terminado vá em Tools|Options|Debugger|General e ligue a opção Show message on stop with Error (exit Code<>0):
Com a opção acima ligada, veja o que acontece quando terminamos o programa com ‘exit code’ diferente de zero:
Para se aproveitar do ‘exit code’ precisamos saber como nosso sistema operacional dá acesso a ele, só assim saberemos como escrever scripts ou criar agendamentos de tarefas que usufruam dessa informação. Veja como obtemos o ‘exit code’ no Windows/Terminal:
No exemplo acima, vimos que nosso programa terminou com ‘exit code’ igual a 2 conforme o esperado. Usamos a variável de ambiente %ERRORLEVEL% do cmd.exe para enxergá-la. No Linux essa variável de ambiente seria $?. Para usufruir do ‘exit code’ dentro de scripts faríamos assim no Windows:
meuaplicativo.exe
if %ERRORLEVEL% neq 0 (
(...)
)
No Linux, faríamos assim:
meuaplicativo.exe
if [ $? -ne 0 ] ; then
(...)
fi
Agora podemos criar scripts bat/vbs/python/bash,… onde executamos nosso programa e se retornar algo diferente de zero poderemos abortar o script ou enviar uma notificação por email, por exemplo.
Agora que nosso programa é capaz de enviar mensagens para stdout/stderr podemos agendar sua execução com redirecionadores. No Linux há até padrões no serviço de log onde mensagens enviadas para stderr são tratadas indistintamente geralmente levando-as para arquivos de log, mas no Windows é complicado, ele tem um visualizador de eventos, mas não é um serviço plugado no stderr e é preciso usar a API dele para enviar algo para ser registrado num de seus logs que por padrão tem a extensão .evt. Então no Windows para que nosso aplicativo seja multiplataforma temos de usar redirecionadores para indicar onde nossas mensagens para o stderr deverão ser salvas:
Com o redirecionador 2>logs.txt todas as mensagens que o nosso programa enviar para stderr serão registradas num arquivo de log chamado logs.txt. Garantimos dessa forma que o log será manuseado pelo sistema operacional usando métodos seguros e dificilmente falíveis. Claro que podemos usar bibliotecas de terceiros para o mesmo fim que talvez exiba numa tela bonita e com mais recursos nossa mensagem, mas se a mesma não usa o stdout/stderr estamos perdendo a habilidade de nosso programa interoperar com outros, incluindo scripts, serviços e agendadores de tarefas.
Concluindo, ao desenvolver seus programas – sejam eles utilitários ou comerciais – façam uso do stdout/stderr e quando seu programa for obrigado a terminar por causa de uma falha, use ‘exit code’ assim você garantirá que seu programa é capaz de interoperar com outros, incluindo scripts, serviços e agendadores de tarefas.