Introdução ao Sistema Operativo Unix e Desenvolvimento de Programas em C Fernando Mira da Silva [email protected] Departamento de Engenharia Electrotécnica Instituto Superior Técnico Setembro de 2000 Índice 1 Introdução 1 2 Unix, GNU/Linux e outros acrónimos 3 2.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.2 Sistemas operativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2.3 Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.1 A génese do Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 2.3.2 Divulgação do Unix . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Computadores pessoais e estações de trabalho . . . . . . . . . . . . . . . . . . . 7 2.4.1 Microprocessadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.4.2 Microcomputadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 2.4.3 IBM-PC e compatı́veis . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.4.4 Interfaces gráficas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.4.5 Estações de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 2.5 Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.6 Cópia e distribuição de software: aspectos legais e acrónimos importantes . . . . 19 2.6.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2.6.2 Código binário e código fonte . . . . . . . . . . . . . . . . . . . . . . . 19 2.6.3 Software proprietário . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.4 II ÍNDICE 2.7 3 4 2.6.4 Software livre, domı́nio público e GPL . . . . . . . . . . . . . . . . . . 21 2.6.5 Freeware e shareware . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 O projecto GNU e o sistema GNU/Linux . . . . . . . . . . . . . . . . . . . . . . 23 Ambiente de trabalho em Unix 25 3.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 Acesso ao sistema . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2.1 Conta de utilizador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2.2 Login e Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 3.3 O sistema de janelas X . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 3.4 Modo interactivo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.4.1 Hierarquia de directórios . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.4.2 Pathnames Absolutos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.4.3 Pathnames relativos . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.5 Comandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 3.6 Dispositivos de entrada e saı́da . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.7 Redireccionamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35 3.8 Pipes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Desenvolvimento de programas 37 4.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 4.2 Assembly e Linguagens de alto nı́vel . . . . . . . . . . . . . . . . . . . . . . . . 37 4.3 Ciclo de desenvolvimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.3.1 Compilação e “linkagem” . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.3.2 Erros sintáticos e semânticos . . . . . . . . . . . . . . . . . . . . . . . . 42 4.3.3 Depuração: gdb e ddd . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 ÍNDICE III 5 4.4 Compilação em módulos separados . . . . . . . . . . . . . . . . . . . . . . . . . 50 4.5 Bibliotecas estáticas e dinâmicas . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.6 O utilitário make . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Editores de texto 57 5.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.2 O editor emacs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.2.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 5.2.2 Modos de edição e de comando . . . . . . . . . . . . . . . . . . . . . . 58 5.2.3 Leitura de ficheiros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 5.2.4 Formatação automática . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.2.5 Compilação e localização de erros . . . . . . . . . . . . . . . . . . . . . 59 O editor vi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.3.1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 5.3.2 Modo de edição . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.3.3 Movimentação do cursor . . . . . . . . . . . . . . . . . . . . . . . . . . 60 5.3.4 Inserir texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.3.5 Apagar texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61 5.3.6 Mudar texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 5.3.7 Procurar texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 5.3.8 Substituir texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 5.3.9 Cortar, copiar e mover texto . . . . . . . . . . . . . . . . . . . . . . . . 63 5.3.10 Outros comandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 5.3.11 Saı́r . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 Os editores pico e joe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 5.3 5.4 IV ÍNDICE 6 Textos e manuais complementares 67 6.1 Sistema Operativo Unix e Linux . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.2 Ambiente de trabalho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 6.3 Programação e depuração de programas em C . . . . . . . . . . . . . . . . . . . 69 Bibliografia 71 Capı́tulo 1 Introdução Pretende-se com este texto introduzir alguns tópicos que facilitem um primeiro contacto com o sistema operativo Unix e ferramentas essenciais ao desenvolvivemento, teste e depuração (debug) de programas em C. Pelo seu carácter introdutório e sumário, este texto não deve ser confundido com um manual do sistema operativo Unix: para este efeito, remete-se o leitor para o capı́tulo 6, onde são listadas diversas referências bibliográficas que aprofundam os tópicos aqui abordados. Para além de funcionar como um manual introdutório ao Unix, são referidos neste texto aspectos históricos e funcionais deste sistema operativo que se espera que contribuam para uma melhor compreensão do posicionamento do Unix no panorama informático actual e, complementarmente, para a introdução de terminologia frequentemente utilizada informática. No capı́tulo 2, apresenta-se uma breve história do sistemas operativo Unix, articulando o seu desenvolvimento com diversos marcos relevantes da história da informática das últimas décadas. No capı́tulo 3 faz-se uma introdução ao ambiente de trabalho em Unix, descrevendo os mecanismos essenciais do sistema de ficheiros, execução de comandos e redireccionamento. No capı́tulo 4 introduz-se a noção de ciclo de desenvolvimento de programas em C e introduzem-se os comandos de compilação em sistemas GNU/Linux. São ainda introduzidos os utilitários gdb, ddd e make. No capı́tulo 5 faz-se uma breve introdução de alguns dos editores de texto disponı́veis em Unix. Finalmente, no capı́tulo 6, são listados textos e bibliografia que aprofundam cada um dos temas abordados. Capı́tulo 2 Unix, GNU/Linux e outros acrónimos 2.1 Introdução Uma introdução ao Unix não implica necessariamente conhecer todos os detalhes da história deste sistema operativo. Mas alguns destes detalhes, além de informativos, são importantes para compreender o posicionamento actual deste sistema operativo. Assim, apresenta-se neste capı́tulo uma breve sı́ntese da evolução do Unix e a sua articulação com outros marcos relevantes da história da informática nas últimas décadas. Esta exposição permitirá também introduzir, de uma forma progressiva, conceitos, terminologia e acrónimos frequentes em informática mas cujo significado é, muitas vezes, mal conhecido. 2.2 Sistemas operativos Não é fácil definir sistema operativo de uma forma rigorosa e abrangente. Numa primeira aproximação, o sistema operativo de um computador pode ser definidido como o conjunto de programas responsáveis pela gestão dos dispositivos e recursos fı́sicos da máquina (hardware) e pelo acesso das aplicações a esses recursos. Considere-se, por exemplo, um programa de processamento de texto desenvolvido para o sistema operativo Windows. Este programa funciona independentemente das caracterı́sticas especı́ficas da máquina em que é executado: em particular, não precisa de conhecer a memória disponı́vel, o tipo especı́fico dos discos utilizados ou o tipo e marca da placa gráfica ligada ao monitor. Com efeito, sempre que é preciso, por exemplo, guardar um ficheiro em disco, o processador de texto limita-se a apresentar este pedido ao sistema operativo, o qual é responsável por o traduzir na sequência de comandos apropriada para o tipo de discos instalados. Complementarmente, é o sistema operativo que permite a execução simultânea de vários programas (por exemplo, um 4 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS processador de texto e uma folha de cálculo), dividindo o tempo de processador disponı́vel pelas duas aplicações. Durante os últimos 50 anos, a evolução dos computadores e da informática foi acompanhada pelo aperfeiçoamento de diversas gerações de sistemas operativos. Pela sua maior divulgação, o MS-DOS, o Windows, o Unix e o Linux (a versão livre1 do Unix) são provavelmente os nomes mais conhecidos de entre os muitos sistemas operativos existentes. 2.3 2.3.1 Unix A génese do Unix “...the number of Unix installations has grown to 10, with more expected...” –Dennis Ritchie e Ken Thompson, autores do Unix, em Junho de 1972. O sistema operativo Unix surge na sequência de um projecto iniciado nos anos 60 nos Bell Labs da AT&T para desenvolver um sistema de operativo de tempo partilhado. Numa época em que os computadores eram máquinas de grande porte e extremamente caras, era da maior importância desenvolver sistemas operativos que permitissem a diversos utilizadores acederem simultaneamente a um mesmo computador e, desta forma, rentabilizar os elevados custos de exploração. Em 1965, os Bell Labs iniciaram um projecto conjunto com a General Electric e o MIT para desenvolver um sistema operativo de tempo partilhado designado Multics. No entanto, pouco depois do seu inı́cio, os Bell Labs consideraram que o projecto estava mal encaminhado e decidiram abandonar o consórcio. Dada a necessidade de ser encontrada uma alternativa ao Multics para uso interno, Kenneth Thompson, um dos investigadores dos Bell Labs, iniciou um projecto de desenvolvimento próprio que conduziu, em 1969, à primeira versão do sistema operativo Unix. Um das inovações do sistema Unix relativamente a outros sistemas operativos da época é o conceito de que muitos dos comandos associados à gestão da máquina devem ser executados por pequenos programas independentes, funcionando de forma cooperativa. Esta estratégia permitiu simplificar significativamente as tarefas associadas ao núcleo2 do sistema operativo, aumentando simultaneamente a sua robustez e modularidade. Uma outra caracterı́stica inovadora do Unix é a sua portabilidade. Até à década de 70, a maioria dos sistemas operativos dependiam fortemente do hardware para que eram desenvolvidos. De 1 Na secção 2.6 discute-se o sentido que “livre” deve ter neste contexto O bloco central do sistema operativo, responsável pela gestão do tempo de processador e partilha de recursos disponı́veis, designado por kernel na terminologia anglo-saxónica. 2 U NIX 5 um modo geral, cada fabricante desenvolvia um sistema operativo especı́fico para os seus computador, o qual era geralmente escrito em assembler (o código binário entendido pelo processador). Frequentemente, uma alteração ou evolução do processador implicava a re-escrita ou a revisão do código de todo o sistema operativo. Ao contrário desta tendência geral, não sendo os Bell Labs fabricantes de computadores, o Unix foi desenvolvido com base numa arquitectura de hardware muito genérica, não se baseando em hipóteses restritivas relativemnte ao tipo de processador utilizado. Assim, embora inicialmente escrito em assembler para um mini-computador PDP-11/20 da Digital, o desenvolvimento da linguagem de programação C por Dennis Ritchie (Kernighan e Ritchie, 1978) em 1973 permitiu a re-escrita de mais 90% do código do sistema operativo nesta linguagem de alto nı́vel. A partir deste momento, a adaptação do sistema operativo a novos processadores é substancialmente simplificada: em vez da re-escrita completa do código binário dos programas que formam o sistema operativo, é suficiente re-escrever o compilador (o programa responsável pela tradução da linguagem C para o código binário do processador), tarefa esta substancialmente mais simples. Após este passo, a adaptação do sistema operativo ao novo processador apenas exige a compilação (tradução automática) dos programas escritos em C. Foram sobretudo as caracterı́sticas de modularidade e portabilidade, aliadas uma boa concepção de raı́z, que permitiram a evolução contı́nua do Unix ao longo de trinta anos e a sua permanente adaptação a múltiplas gerações de hardware e dispositivos periféricos. Neste sentido, o Unix é um caso único de longevidade na área dos sistemas operativos mantendo, ainda hoje, muitas caracterı́sticas avançadas relativamente a a sistemas operativos mais recentes. Por outro lado, em consequência da sua longevidade, é um sistema que ganhou uma fiabilidade elevada, sendo habitual um servidor de Unix estar operacional durante vários meses seguidos, sem qualquer interrupção ou falha do sistema. 2.3.2 Divulgação do Unix Até 1975, o Unix estave confinado internamente aos Bell Labs e só a partir desta data é disponibilizado comercialmente para o exterior. Tendo sido inicialmente concebido para utilização em ambientes relativamente abertos, onde a confidencialidade dos dados não era crı́tica, o sistema Unix foi inicialmente adoptado, sobretudo, por universidades e instituições de investigação. O seu baixo custo e o facto de ser disponibilizado com o código fonte (ou seja, o programa em formato de texto) era especialmente apelativo para as instituições de ensino, já que permitia que os estudantes e investigadores compreendessem e analizassem o seu modo de funcionamento e, adicionalmente, contribuissem com extensões e modificações da versão original. Uma das contribuições mais importantes durante a fase inicial do Unix foi o desenvolvimento, pela Universidade de Berkeley, 6 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS de uma versão para máquinas Vax que incluia suporte para memória virtual3 . Durante o final da década de 70 e a primeira metade da década de 80, a evolução do Unix originou múltiplas variantes. De entre estas, duas tiveram um impacto significativo na evolução seguinte do sistema operativo. A primeira, resultante da investigação e densenvolvimento dentro dos próprios laboratórios Bell, inclui já em 1979 (Unix 7a edição) um mecanismo eficiente de comunicação entre computadores. Este mecanismo, designado UUCP, (Unix to Unix CoPy), será amplamente utilizado até ao aparecimento do protocolo TCP/IP (o principal protcolo actualmente utilizado na Internet). Esta evolução dá origem em 1983 ao designado Unix Sistema V. Em 1991 é formado o USL (Unix System Laboratory, uma companhia maioritariamente detida pela AT&T), que passa a deter os direitos sobre o Unix. Em 1993 a USL é adquirida pela Novell, a qual, por sua vez, passará mais tarde os direitos sobre a marca Unix para o consórcio X/Open. Paralelamente, a Universidade de Berkeley desenvolve uma evolução do sistema Unix que recebe a designação BSD que inclui, como principal inovação, um eficaz sistema de comunicação entre processos (programas), baseado na noção de sockets. Este modelo é suficientemente genérico para permitir não apenas a comunicação entre programas residentes no mesmo computador, como também a comunicação entre programas executados em computadores diferentes e ligados pelo protocolo TCP/IP. Este mecanismo, que virá mais tarde a ser adoptado também por outros sistemas operativos, é ainda hoje a base da maioria das comunicações estabelecidas na internet, como seja a ligação entre um browser (como por exemplo o Netscape ou o Internet Explorer) e uma máquina remota (server) que disponibiliza a informação. Durante a década de 80 e inı́cio da década de 90, os principais fabricantes de computadores apercebem-se da importância crescente do Unix. De modo a adaptarem-se a esta realidade, diversos fabricantes licenciam o código fonte da AT&T e, com base neste, desenvolvem versões proprietárias do Unix. É assim que a Digital lança o Ultrix, a HP o HP-UX, a Sun o SunOS, e a IBM o AIX, entre outros. Trata-se de um perı́odo de grande expansão e popularidade das diversas variantes do sistema operativo Unix, sobretudo nos meios académicos. Enquanto a divulgação do Unix aumenta, um outro projecto que terá amplas repercussões na área da informática conhece também avanços importantes. Em 1973, o departamento de Defesa Americano tinha iniciado o Defense Advanced Research Projects Agency (DARPA). O objectivo era desenvolver uma arquitectura de rede com uma gestão distribuı́da, tal que o funcionamento no seu conjunto não fosse afectado pela inoperacionalidade de qualquer dos seus nós. Este objectivo era justificado pela Guerra Fria, então no seu auge, e pelos cenários estabelecidos pelos estrategas 3 A possibilidade, hoje comum, de um sistema utilizar mais memória do que a RAM efectivamente disponı́vel através de um sistema de armazenamento e automático em disco de zonas da memória menos usadas, e a sua posterior leitura quando necessário. C OMPUTADORES PESSOAIS E ESTAÇ ÕES DE TRABALHO 7 militares em caso de guerra nuclear. O projecto incluı́a o desenvolvimento de protocolos4 que permitissem uma comunicação transparente entre dois computadores ligados em rede, mesmo quando uma mensagem tivesse que atravessar diversas máquinas entre a origem e o destino. Este projecto foi designado de Internetting, e o sistema de computadores interligado que emergiu deste trabalho foi designado pelo então obscuro nome de Internet. Os protocolos que foram desenvolvidos no âmbito deste projecto vieram a ser conhecidos por TCP/IP: Transmission Control Protocol (TCP) e Internet Protocol (IP). Em 1986 a National Science Foundation inicia o desenvolvimento da NFSNET, financiando a criação de um amplo sistema de nós interligados no Estados Unidos que formam o esqueleto inicial da Internet. Até 1993, data de aparecimento dos primeiros broswer, a Internet é sobretudo utilizada pelos meios académicos e de investigação. No processo de crescimento da Internet, o sistema operativo Unix tem também um papel fundamental, pelas suas caracterı́sticas de interoperabilidade e pelo suporte principais protocolos de comunicação baseados no TCP/IP então usados na rede: o SMTP (Simple Mail Transfer Protocol), utilizado pelo correio electrónico e o FTP (File Transfer Protocol). O facto de muitos dos nós da rede serem baseados em máquinas Unix contribuı́u também significativamente para o crescimento e popularidade de um sistema operativo que, progressivamente, extravasou os meios académicos e começou a afirmar-se como uma alternativa viável em certos contextos empresariais. Entratanto, no inı́cio da década de 80, tinham entrado em cena os chamados computadores pessoais. Originalmente muito limitados na sua capacidade computacional, concebidos como postos de trabalho individuais e com sistemas operativos muito simples, era difı́cil imaginar que alguma vez viessem a concorrer com os computadores de médio e grande porte, onde pontificavam os sistemas operativos multi-tarefa e multi-utilizador, entre os quais se encontrava o Unix. O tempo veio, no entanto, a provar o contrário. 2.4 2.4.1 Computadores pessoais e estações de trabalho Microprocessadores Até à década de 60, a unidade central de processamento de um computador ocupava diversas placas electrónicas, povoadas por transistores, condensadores e resistências. Acomodar todo este equipamento exigia um espaço fı́sico relativamente amplo. Embora com diversas variantes consoante a capacidade de cálculo, os mais pequenos computadores desta geração dificilmente podiam ser arrumados no canto do escritório. O primeiro sinal de mudança surge em 1971, quando a Intel anuncia o desenvolvimento do 4 A linguagem ou diálogos de entendimento utilizados na comunicação entre computadores. 8 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS primeiro microprocessador, um circuito integrado que inclui num único chip a maioria dos componentes normalmente encontrados na unidade central de processamento de um computador. Apesar do Intel 4004 ser um processador de apenas 4 bits, constitui um marco decisivo na história do hardware. No ano seguinte, enquanto Nolan Bushnell, da Atari, cria o primeiro jogo de vı́deo, a Intel lança o 8008, um microprocessador de 8 bits, cuja evolução origina, em 1973, o 8080. Inicialmente, os microprocessadores são utilizados apenas como dispositivos de controlo industrial. Em 1974, a Scelbi Computer Consulting utiliza o 8080 como base de um pequeno computador pessoal, de divulgação muito restrita. Nascem assim os microcomputadores, designação que deriva da sua unidade central de processamento ser um microprocessador. No mesmo ano surge o Mark 8, um microcomputador em kit que só os entusiastas de electrónica mais persistentes conseguem pôr a funcionar. No entanto, estes primeiros microcomputadores têm uma divulgação muito restrita. Para o público em geral, o microprocessador é uma entidade desconhecida, e apenas o aparecimento e rápida divulgação das máquinas de calcular de bolso indicia que algo está a mudar ao nı́vel da miniaturização e integração da electrónica digital. 2.4.2 Microcomputadores Em Dezembro de 1974, surge o primeiro computador pessoal com alguma divulgação comercial: o Altair 8800, produzido pela MITS, que tinha também por base o microprocessador 8080, e que dispunha da uma descomunal memória de 256 bytes (não, não falta o K, estamos a falar de duzentos e cinquenta e seis bytes, ou seja, 1/4 de Kbyte) e era vendido por cerca de 500 dólares. Quando o Altair foi pela primeira vez anunciado na revista Popular Electronics, os fabricantes receberam 400 encomendas na primeira tarde. Pelos parâmetros actuais, o Altair dificilmente poderia ser considerado um verdadeiro computador: a introdução de dados era realizada em código binário por um conjunto de interruptores que substituia o teclado. Os resultados das operações eram apresentados, também em código binário, num conjunto de pequenas lampadas (leds) da caixa. Nesta versão inicial, o Altair não era mais que um dispositivo onde se podiam programar, muito trabalhosamente, sequências elaboradas de operações lógicas. Embora revolucionário para os interessados em electrónica digital, o Altair original tinha um interesse prático limitado. Entre os leitores do anúncio do Altair na Popular Electronics estavam dois estudantes de Harvard, com um forte interesse em informática: Paul Allen e William Gates(Williams, 1993). Rapidamente os dois estudantes anteciparam o potencial do Altair, desde que dotado com software apropriado. Em particular tiveram a intuição de que o hardware do Altair era suficiente para suportar um interpretador de uma linguagem de alto nı́vel, desde que fosse ligado a uma simples C OMPUTADORES PESSOAIS E ESTAÇ ÕES DE TRABALHO 9 teleimpressora5 . Não é possı́vel estabelecer com rigor os detalhes da história que se segue, já que o tempo leva a que a realidade e o mito por vezes se confundam. Consta que Bill Gates, então com 19 anos, telefona à MITS e afirma dispôr de um interpretador de Basic adequado ao Altair. A MITS mostrase interessada em testar o interpretador. Aparentemente Bill Gates não tinha uma única linha de programa escrita quando prometeu o Basic à MITS, o que faz deste um dos primeiros componentes de vaporware6 do mercado informático. Dado que Allen e Gates não dispunham de um Altair para desenvolver o seu interpretador de Basic, Allen desenvolveu um simulador de um microprocessador 8080 no PDP-10 de Harvard7 enquanto que Gates se dedicou ao desenvolvimento do interpretador de Basic. Oito semanas depois, Allen deslocou-se à MITS com a missão de testar o interpretador. Foi o seu primeiro contacto real com o Altair e, aparentemente a demonstração de Allen impressionou positivamente a MITS.8 Em 1976, após um ano de comercialização bem sucedida do Basic para o Altair, Bill Gates funda a Microsoft. Praticamente ao mesmo tempo, também em 1975, um técnico da HP em Palo Alto, Steve Wozniak, fazia planos para construir o seu próprio computador pessoal. Em vez do microprocessador 8080 da Intel, Wozniak preferiu adoptar o processador 6800 da Motorola, apenas por este ser mais barato. Wozniak planeou de raı́z a sua máquina para incluir um teclado e uma interface para televisão (obviamente a preto e branco), de forma a ultrapassar as limitações iniciais do Altair. O computador de Wozniak evoluiu com a colaboração activa de um colega de 21 anos chamado Steve Jobs. Ao fim de algum tempo, este sugeriu a Wozniak a comercialização do sistema desenvolvido. Em Abril de 1976, Wozniak e Jobs fundam a Apple Computer Company. Em Julho de 1976, é comercializado o Apple I. A primeira vez que o Apple I foi apresentado numa reunião da Association of Computer Machinery, muitos dos presentes pensaram que se tratava de um terminal ligado telefonicamente a um computador de grande porte, já que era difı́cil, na altura, acreditar que as potencialidades demonstradas pela máquina tivessem origem na pequena caixa visı́vel ao público. O Apple II, lançado em 1977, é o primeiro sucesso comercial da Apple. 5 Máquina de escrever electromecânica com uma porta série. Na gı́ria informática, vaporware designa um programa anunciado por um fabricante muito antes da sua produção e, frequentemente, com especificações prometidas difı́ceis ou impossı́veis de cumprir. 7 Anos mais tarde, o conhecimento da utilização dos recursos de Harvard para este efeito deu origem a alguma polémica. 8 Segundo a versão oficial da Microsoft, o interpretador de Basic funcionou em pleno no primeiro teste real. Face às difı́ceis condições de desenvolvimento, esta afirmação deve ser encarada com algum cepticismo, sem que este facto retire qualquer mérito ao excelente trabalho de Allen e Gates. 6 10 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS 2.4.3 IBM-PC e compatı́veis Nos anos seguintes, os modelos dos chamados computadores pessoais multiplicam-se, embora o seu preço confine a sua utilização às empresas. A IBM, à data o maior fabricante mundial de computadores de grande porte, olhara incialmente este mercado emergente com alguma sobranceria. O sucesso do Apple II leva a IBM a aperceber-se finalmente das potencialidades desta classe de produtos e a iniciar o desenvolvimento do seu próprio modelo de computador pessoal, com o nome de código de Acorn. Trata-se de um projecto que decorre em moldes pouco ortodoxos para os hábitos da empresa. De forma a reduzir o custo final da máquina, o projecto Acorn é baseado em componentes disponı́veis no mercado, em vez de seguir a polı́tica habitual na IBM de desenvolver componentes proprietários. Em particular, é decidido adoptar o processador 8088 da Intel para unidade central de processamento (CPU) do Acorn. Como se verá, esta decisão terá amplas repercussões no seguimento. Entretanto, a Microsoft continuava a crescer, centrando a sua actividade no desenvolvimento de software, sobretudo interpretadores e compiladores. Em 1980, numa tentativa para diversificar a sua actividade, a Microsoft tenta entrar na área dos sistemas operativos e anuncia o inı́cio do projecto Xenix, um sistema operativo baseado no Unix que seria suportado em diversos processadores. Aproximadamente nesta altura, a IBM necessita de dotar o Acorn com um sistema operativo simples e eficiente e, mais uma vez, resolve recorrer ao mercado em vez de utilizar os seus próprios recursos. É assim que têm inı́cio os contactos entre a IBM e a Microsoft, dada a experiência desta última no desenvolvimento de software para os microprocessadores de 8 bits da Intel. Apesar do anúnico do projecto Xenix, este encontrava-se em fase embrionária e a Microsoft não dispunha de experiência real em sistemas operativos. O melhor sistema operativo para microprocessadores disponı́vel à época era o CP/M (Control Program for Minicomputers), desenvolvido por Gary Kindall, da Digital Research. Tim Paterson, um programador da Seattle Computer Products, tinha desenvolvido um protótipo de sistema operativo para um computador 8086 que retinha alguns aspectos do funcionamento do CP/M, mas que era suficientemente diferente deste para não infringir as regras de copyright. Patterson designou o seu sistema operativo de QDOS, acrónimo de Quick Disk Operating System, mas que os mais crı́ticos não hesitam a identificar como Quick and Dirty Operating System. A Microsoft, sem referir o acordo que tinha com a IBM, comprou os direitos do QDOS à Seattle Computer Products por uma importância irrisória e, após algumas modificações, surgia a primeira versão do MS-DOS, o sistema operativo de que a IBM necessitava. Bill Gates licencia o MS-DOS à IBM, mas consegue que a Microsoft retenha o direito de comercialização do MS-DOS. Anos mais tarde, Tim Paterson ingressará na Microsoft. Em Agosto de 1981 a IBM anuncia públicamente o resultado do projecto Acron sob a designação de IBM-PC, uma máquina baseado num processador 8088 a 4.77Mhz, uma memória C OMPUTADORES PESSOAIS E ESTAÇ ÕES DE TRABALHO 11 de 16Kbytes, expansı́vel até 256Kb, e com uma ou duas unidades de diskettes. Este modelo, cuja evolução deu origem aos actuais PCs9 , tem um sucesso que ultrapassa largamente as expectativas da própria IBM. Além da aura da marca, a arquitectura aberta do sistema permitia o fácil desenvolvimento de software e hardware por parte de outras empresas. O modelo evolui e, em 1983, quando a IBM lança o IBM-XT, este lidera largamente o mercado dos computadores pessoais. A oferta de software para nova máquina cresce e a introdução da folha de cálculo Lotus faz o interesse pela máquina por parte das empresas subir em flecha. Também fabricantes de hardware contribuem para este sucesso, com o desenvolvimento de placas gráficas melhoradas e outros periféricos. A arquitectura aberta do IBM-PC, e o seu successo comercial, leva a que construtores independentes comecem a tentar desenvolver máquinas equivalentes. Rapidamente são encontados circuitos de substituição para os poucos componentes do IBM-PC que são proprietários da IBM. Surgem assim os chamados PC-compativeı́s ou clones, máquinas de menor custo que as comercializadas pela IBM, mas que são capazes de correr o mesmo software. Esta possibilidade é facilitada pelo facto da IBM não deter o exclusivo do sistema operativo MS-DOS, o qual é vendido pela Microsoft a qualquer fabricante ou utilizador que o pretenda. Como é evidente, o aparecimento de clones é mal recebida pela IBM, mas revela-se um negócio extremamente lucrativo para a Microsoft, que vê as suas vendas aumentarem significativamente. A década de 80 é um perı́odo de crescimento e grande divulgação da microinformática. Enquanto os IBM-PC e compatı́veis10 se afirmam sobretudo como postos de trabalho individuais nas empresas, surge em 1982 o ZX-Spectrum, um pequeno computador baseado no processador Z80 da Zilog, de custo muito reduzido (o Spectrum não dispunha de diskettes mem de monitor, e o seu funcionamento exigia a ligação de uma televisão e de um gravador de cassetes para a gravação e leitura de dados), que dominará o mercado doméstico e de jogos até 1987. Outras marcas surgem na altura com os seus próprios modelos, alguns com grande sucesso no mercado, como a Commodore Amiga e a Compaq. Mas o único concorrente sério ao domı́nio absoluto dos IBM-PC e compatı́veis irá surgir da Apple, pela mão de Steve Jobs. 2.4.4 Interfaces gráficas Desde o aparecimento dos primeiros computadores na década de 40 e até meados da década de 80, a comunicação com os computadores era fundamentalmente realizada em modo de texto, como sucede no modo MS-DOS do Windows. O utilizador digitava um comando escrito e o computador executava-o, eventualmente enviando para o dispositivo de saı́da uma resposta sob a forma de uma sequência de linhas de texto. 9 De facto, qualquer PC actual é ainda capaz de executar o software desenvolvido para o IBM-PC original. De aqui adiante, seguindo uma terminologia hoje muito generalizada, designar-se-á os IBM-PC e compatı́veis simplesmente por PCs, mantendo no entanto presente que a designação é algo abusiva relativamente a outros fabricantes. 10 12 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS No inı́cio da década de 60, Ivan Sutherland, então um estudante de Doutoramento do MIT, tinha desenvolvido um sistema que permitia a elaboração de desenhos em computador sobre um tubo de raios catódicos. Os desenhos assim desenvolvidos podiam ser escalados, apagados e copiados. Embora o sistema tivesse uma estrutura primitiva pelos parâmetros actuais, a tese de Doutoramento de Sutherland, entitulada ”Sketchpad: A Man-machine Graphical Communications System”, discutia pela primeira vez a importância de sistemas gráficos de interacção homem-máquina, que virão mais tarde a ser conhecidos sob a sigla GUI, de Graphical User Interface. Durante a década de 70, a Xerox cria um grupo de investigação nos laboratórios PARC (Palo Alto Research Center) dedicado à análise e estudo da interacção homem-máquina. A equipa inclui não apenas engenheiros, mas também psicólogos que investigam mecanismos essenciais da aprendizagem humana. O trabalho desenvolvido no Xerox PARC inventa ou aprofunda muitos conceitos hoje correntes na interacção com computadores: a representação de ficheiros e comandos num écran sob a forma de ı́cones, a utilização de dispositivos apontadores (ratos ou canetas) para manipular estes objectos, a co-existência num mesmo écran de diversas janelas com informação referente à execução de diferentes programas. Em particular, é desenvolvido o conceito WYSIWYG (What You See Is What You Get) em editores gráficos e de texto, baseado no princı́pio de visualização directa e interactiva no monitor do resultado final do processamento. No inı́cio da década de 80, apesar do sucesso comercial dos Apple II e Apple III, a Apple tinha começado a perder terreno devido ao recém chegado IBM-PC. Steve Jobs, que tinha visitado o Xerox PARC e ficado impressionado com o trabalho ali desenvolvido, apercebe-se que as interfaces gráficas podem ser a resposta adequada ao progressivo domı́nio da IBM no mercado. É assim que a Apple dá inicio a um projecto de investigação em interfaces gráficas para o qual são contratados muitos dos investigadores do Xerox PARC. A Apple aprofunda e melhora os conceitos ali desenvolvidos, os quais serão implementados numa versão primitiva no modelo Lisa da Apple, em 1982. A evolução deste modelo conduz à apresentação em 1984 do Macintosh o qual, equipado com o sistema operativo MacOS, é a primeira implementação comercial de uma interface gráfica simultaneamente eficiente e intuitiva. A introdução do Macintosh traz uma revolução à área dos computadores pessoais e o seu sucesso comercial é enorme. No entanto, dois factores contribuem para a limitar este sucesso: o preço muito mais elevado dos Macintosh e a arquitectura aberta do IBM-PC. Esta última tinha permitido o contı́nuo crescimento dos fabricantes de compatı́veis, arrastando atrás de si fornecedores de hardware e software e, consequentemente, uma redução contı́nua de preços. A Apple, em contrapartida, baseava-se num modelo de hardware e sistema operativo proprietários, o que lhe permitia uma maior margem de manobra e o controlo do produto mas, simultaneamente colocava fortes limitações às contribuições externas. Apesar de manter o domı́nio comercial, a IBM apercebe-se do potencial da interface gráfica do Macintosh. No entanto, por limitações do hardware, a implementação de um sistema com- C OMPUTADORES PESSOAIS E ESTAÇ ÕES DE TRABALHO 13 parável nos IBM-PC não era viável a curto prazo. O hardware do Macintosh tinha sido concebido de raı́z incluindo processadores de sinal e primitivas gráficas sofisticados. Também o sistema operativo MacOS era incomparavelmente mais sofisticado que o MS-DOS, o que dava à Apple um confortável avanço em matéria de interfaces gráficas e multimédia. Em 1985, a IBM e a Microsoft dão origem a um projecto conjunto para desenvolvimento de um Sistema Operativo com interface gráfica designado OS/2. Apesar deste projecto comum ser publicamente anunciado e conduzir, em 1987, à primeira versão do OS/2, a Microsoft continua a dedicar recursos significativos ao desenvolvimento de um sistema gráfico próprio, designado Windows. Depois de duas versões pouco apelativas, a Microsoft apresenta em 1990 o Windows 3.0, o primeiro concorrente sério, pela qualidade da interface gráfica, ao MacOS apresentado seis anos antes. A Apple abre um processo contra a Microsoft protestando pela cópia da interface do MacOS e pela infracção de direitos de autor. A Microsoft argumenta com a autoria original das interfaces gráficas, que atribui ao trabalho desenvolvido no Xerox PARC, dando origem a um dos mais complexos processos judiciais da história da informática. Este só terminará em 1997, com um acordo entre as duas empresas conduzido respectivamente por Bill Gates e Steve Jobs. Este acordo tem como pano de fundo o lançamento em 1995 do Windows 95, cujo domı́nio comercial tinha colocado em fortes dificuldades a Apple. Outra vı́tima do sucesso do Windows e da Microsoft foi o OS/2, cujo desenvolvimento nunca tinha sido abandonado pela IBM e que tinha conduzido a um sistema operativo que, em meados da década de 90, era amplamente reconhecido como superior ao Windows em termos de eficiência e robustez. A falta de software que explorasse as suas caracterı́sticas é no entanto penalizador e nem o derradeiro esforço da IBM em 1995/96, perı́odo em que procedeu uma distribuição massiva e frequentemente gratuita do OS/2, permitiu que este obtivesse uma quota de mercado significativa. 2.4.5 Estações de trabalho Durante a década de 80, enquanto os microcomputadores marcavam a sua presença no mercado das máquinas de gama baixa, os utilizadores especializados continuavam a necessitar de máquinas mais potentes, com sistemas operativos multi-tarefa e multi-utilizador. Os sistemas de grande porte (mainframes), normalmente associados so suporte de transacções em bases de dados de grande dimensão, eram dominados por empresas como a IBM, Univac ou a Honeywell. Entre estas e os computadores pessoais situavam-se os chamados minicomputadores, máquinas muito mais pequenas do que as anteriores mas, ainda assim, consideravelmente mais potentes que os PCs. Os minicomputadores eram geralmente disponibilizados com sistemas operativos multitarefa e multiutilizador, e tinham a dimensão apropriada para suprir as necessidades de um grupo de investigação ou de um departamento de uma empresas (por exemplo, uma agência bancária). Originalmente, o acesso quer aos computadores de grande porte quer aos minicomputado- 14 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS res era realizado apenas por meio de terminais alfanuméricos, ligados por uma linha série. A ligação era lenta e, obviamente, só possı́vel em modo de texto. Apesar de terem velocidades de processamento muito inferiores, os computadores pessoais tinham a vantagem de poder aceder directamente à memória de vı́deo da máquina, permitindo a manipulação e alteração das imagens no écran de forma muito rápida. É por este motivo que aplicações como a folha de cálculo11 ou os jogos, aplicações que exigem uma forte interacção entre o software e a imagem gráfica, surgem de facto primeiro nos computadores pessoais do que em máquinas mais potentes. A associação de minicomputadores a monitores gráficos, permitindo a que os processadores acedam directamente à memória de vı́deo, deu origem às chamadas estações de trabalho ou workstations. Inicialmente, as estações de trabalho têm um preço elevado, sendo apenas adoptadas em aplicações especializadas que requerem computação gráfica intensiva, sobretudo na área da engenharia. Em 1984, o MIT inicia o desenvolvimento do sistema de janelas X para estações de trabalho com sistemas operativos Unix. O X Windows é um sistema consideravelmente mais complexo que os sistemas gráficos dos computadores pessoais. Nestes últimos, a gestão do écran é efectuada directamente pelos programas ou pelo sistema operativo. De acordo com a filosofia modular do sistema Unix, o sistema gráfico X Windows não faz parte do sistema operativo, sendo constituido por um conjunto de programas autónomos responsáveis apenas pela gestão do sistema gráfico. O modo de funcionamento do protocolo X segue o chamado modelo cliente-servidor. Assim, uma única aplicação (o servidor) é responsável pela gestão directa do écran e hardware gráfico. As aplicações que necessitam de usar o écran como, por exemplo, um browser de internet ou um editor gráfico, constituem os chamados programas clientes, que se limitam a enviar pedidos de manipulação de imagens para o servidor. Uma das grandes vantagens deste modelo é o facto de um programa cliente poder ser executado numa máquina diferente daquela em que se encontra fisicamente instalado o hardware gráfico e o programa servidor, desde que as duas máquinas estejam ligadas em rede: como já referido anteriormente, o modelo de comunicação entre programas ou processos em Unix é idêntico quer estes se encontrem no mesmo computador ou em computadores diferentes ligados em rede. A evolução do X Windows, que conhece grande divulgação sobretudo a partir da versão X11, aliada à progressiva redução dos preços dos minicomputadores, permitiu que as estações de trabalho, originalmente utilizadas apenas em ambientes que necessitavam de computação gráfica avançada, se generalizassem como a interface preferencial para máquinas Unix. As estações de trabalho baseadas em minicomputadores tiveram o seu perı́odo de maior divulgação no final dos anos 80 e inı́cio dos anos 90. Durante este perı́odo, o hardware dos minicomputadores sofreu também uma evolução significativa, com a generalização dos chamados processadores RISC (Reduced Instruction Set Computers), com os quais se obtiveram aumentos significativos na velocidade de processamento. 11 A folha de cálculo foi inventada por Dan Bricklin, tendo sido originalmente desenvolvida num Apple II e comercializada sob o nome de VisiCalc em 1979. L INUX 15 Apesar de serem adoptadas em múltiplas áreas da investigação e da engenharia, as estações de trabalho ficaram sobretudo conhecidas pelo seu papel em trabalhos de animação por computador e na colorização e recuperação de filmes, áreas em que, ainda hoje, têm uma importância significativa. 2.5 Linux “Linux is obsolete. (...) Be thankful you are not my student. You would not get an high grade (...)” E-mail do Prof. Tanenbaum a Linus Torvalds, em 1992, criticando a arquitectura monolı́tica do Linux e profetizando o seu desaparecimento a curto prazo. No inı́cio dos anos 90, o panorama da Informática era dominado pelo crescimento da Internet, a qual, embora ainda estranha às empresas, conhecia progressiva divulgação nos meios académicos e de investigação. Como já se referiu, o mercado era dominado, nos postos de trabalho individuais pelos compatı́veis dotados com o MS-DOS/Windows, embora o Macintosh tivessem uma fracção importante do mercado, sobretudo em áreas editorias. As estações de trabalho Unix com X11 dominavam em ambientes especializados e, tipicamente, apresentavam velocidades de processamento dez vezes superiores às dos computadores pessoais, embora à custa de um preço também várias vezes superior. Em redes locais de média dimensão, as máquinas Unix eram também frequentemente adoptadas como servidores de rede, gerindo serviços centralizados como o correio electrónico, sistemas de backup, impressoras, áreas de disco partilhadas, servidores de web e interligação à internet.12 No topo, os mainframes completavam o quadro, normalmente ao serviço de grandes bases de dados. Nesta altura, o hardware dos PCs tinha também já conhecido uma evolução significativa. Os processadores 386 e 486 da Intel, predecessores dos Pentium, tinham já suporte para os mesmos mecanismos avançados de computação disponı́veis nos minicomputadores e, embora mais lentos, dispunham de uma arquitectura de 32 bits, suporte para memória virtual e funcionamento em modo protegido. Estas potencialidades constratavam com as arquitecturas muito simplificadas do DOS/Windows, as quais só funcionavam modo de 16 bits e praticamente não exploravam as potencialidade dos novos processadores. Embora este facto fosse em parte ditado pela exigência do mercado em manter a compatibilidade total dos PCs com a enorme quantodade de software desenvolvido para o DOS original, tratava-se sem dúvida de um subaproveitamento significativo do hardware disponı́vel. Para além do DOS/Windows, praticamente não existiam nesta altura sistemas operativos al12 Por oposição à designação de servidor (server), os postos de trabalho individuais são frequentemente designados por clientes, no sentido em que são consumidores dos serviços disponibilizados pelo servidor. 16 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS ternativos para os PC’s. O projecto OS/2 tinha pouca divulgação. A Microsoft tinha já iniciado internamente o projecto do Windows NT, um sistema operativo com núcleo multitarefa que viria a preencher a oferta da Microsoft no mercado de servidores, mas que só seria anunciado em 1993. Nesta altura, muitos utilizadores de Unix em empresas e instituições de ensino dispunham de PC’s em casa com DOS/Windows. No entanto, a possibilidade de usar os PCs domésticos para desenvolver software Unix era limitada. O Xenix, a variante de Unix da Microsoft, desenvolvido a partir de código licenciado pela ATT, estava disponı́vel desde meados dos anos 80. No entanto, o Xenix tinha tido a sua origem com os processadores Intel 80286, que não dispunham ainda de suporte para memória virtual. Tratava-se, portanto, de uma implementação limitada de Unix e pouco compatı́vel com o software disponı́vel nas estações de trabalho Unix de gama média. Em 1987, Andrew S. Tanenbaum, um Professor de Sistemas Operativos em Berkeley, tinha desenvolvido o Minix, um sistema operativo baseado numa arquitectura designada por microkernel. Relativamente ao modelo do Unix (designado monolı́tico), as arquitecturas de microkernel simplificam ainda mais as funções do núcleo, isolando as tarefas de gestão de memória e de gestão de ficheiros do núcleo propriamente dito. O Minix tinha uma arquitectura elegante e avançada, era compatı́vel com diversas plataformas de hardware e, ao nı́vel do utilizador, tinha uma interface similar aos sistemas Unix. Tanembaum tinha desenvolvido o Minix como um hobby e, sobretudo, como uma ferramenta de ensino. O Minix teve um sucesso razoável junto de estudantes e investigadores de sistemas operativos, tendo dado origem a um grupo de discussão na internet com cerca de 40,000 pessoas. No entanto, apesar das suas potencialidades, a filosofia de microkernel do Minix tinha também várias limitações de ordem prática. Apesar da forte dinâmica do grupo de discussão, com utilizadores constantemente a solicitar, sugerir ou a enviar alterações e adições, Tanenbaum mostrava-se, na maioria dos casos, extremamente relutante em incorporar estas contribuições no seu kernel. Na maioria dos casos, Tanenbaum considerava as alterações sugeridas como desnecessárias e ameaçadoras da simplicidade e caracterı́sticas pedagógicas do seu microkernel. Esta opção limitava, no entanto, o nı́vel de utilização do Minix. Adicionalmente, Tanenbaum tinha decidido manter o código propritetário, sendo a licença comercializada, embora a preço reduzido, através da Prentice-Hall. Da comunidade de utilizadores e estudantes de Minix fazia parte um estudante finlandês, de 20 anos, da Universidade de Helsinquia chamado Linus Torvalds. Em 1991 Linus tinha adquirido um PC com um processador Intel 80386 e, tal como muitos outros elementos da comunidade Minix, pretendia que este evoluisse de modo a poder executar o enorme manancial de software disponı́vel para sistemas Unix. Linus tinha apenas cerca de um ano de experiência na linguagem de programação C quando decidiu começar a implementar um kernel próprio para teste de alguns aspectos do sistema Unix. A estratégia seguida por Linus partiu da modificação e extensão do Minix de modo a este implementar o modelo Unix. É provável que, para este processo, tenha L INUX 17 contribuı́do o recém publicado livro de M. Bach, Design of the Unix Operating System (Bach, 1986), o qual descrevia de forma pedagógica e clara muitos detalhes do sistema Unix. Em 1991, Linus envia uma mensagem para o grupo de discussão de Minix na Internet anunciando que estava a desenvolver um pequeno kernel de Unix para PC’s gratuito e que aceitava sugestões para e e colaboração. Para muitos analistas, o inı́cio do projecto só terá sido possı́vel pela relativa ingenuidade de Linus relativamente à complexidade que este apresentava. Na especificação inicial do Linux encontrava-se a adesão ao standard POSIX, que descrevia um conjunto de normas de comunicação entre aplicações e o sistema operativo que facilitava a portabilidade de programas entre diferentes sistemas operativos. O POSIX, embora inspirado em muitas interfaces de sistema do Unix, foi definido de forma a ser adoptado por outros sistemas operativos. Este facto favorecia a compatibilidade do Linux com novas aplicações. Pouco tempo depois, a maioria da comunidade Minix aderia ao Linux,13 e começaram a chegar a Linus inúmeras sugestões, correcções, contribuições e drivers para suporte de vários dispositivos. Independentemente do inegável mérito pessoal do trabalho de Linus Torvalds, diversos factores contribuı́ram para o sucesso do Linux. O mais decisivo foi, sem dúvida, a rapidez com que a primeira versão utilizável foi disponibilizada na internet, cobrindo uma lacuna existente na área dos sistemas operativos para PCs e ultrapassando outros projectos então em fase de preparação. Com efeito, a GNU (ver secção 2.7) tinha desde a sua criação um projecto de desenvolvimento de um sistema operativo, mas este nunca ultrapassou a fase de especificação. Também a Universidade de Berkeley desenvolvia na altura o 386BSD, que evoluı́u mais tarde para FreeBDS, uma versão de Unix por muitos considerada superior ao Linux,14 mas a sua divulgação foi atrasada por problemas legais derivados da reutilização de partes do código original do Unix da ATT, além de Berkeley ter adoptado uma polı́tica de distribuição mais restritiva que a seguida por Linus. Outro factor decisivo para o sucesso do Linux foi o seu aparecimento na altura em que a internet interligava, pela primeira vez, as principais instituições universitárias e de investigação de todo o mundo. Este facto foi fundamental para o desenvolvimento um projecto de programação fundamentalmente cooperativo. De facto, embora o código de Linus tenha formado a base do núcleo do Linux, foi a sua arquitectura aberta e as contribuições de centenas de programadores que despoletaram o crescimento e divulgação do Linux a partir de 1992. Destacam-se, entre outros, Alan Cox, provavelmente o maior contribuidor individual para o núcleo do Linux e até agora responsável pela organização e distribuição do código do núcleo. Durante o final da década de 90, o aumento da capacidade de processamento dos processa13 Facto que não foi facilmente aceite por Tanenbaum, que considerava a arquitectura do Linux obsoleta e inaceitável, tendo dado origem a um hoje célebre debate na internet entre os defensores do Minix e Linux (Tanenbaum e outros, 1993). Em defesa deste último surgiu, entre muitos outros, Ken Thompson. 14 Anos mais tarde, Linus afirmou que o projecto Linux não teria tido inı́cio caso o BSD tivesse surgido algum tempo antes. 18 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS dores Intel conduziu a uma redução significativa do fosso que separava os PCs das Workstations baseadas em processadores RISC em termos de desempenho. Equipados com Linux e podendo agora correr as mesmas aplicações anteriormente só disponı́veis em máquinas de gama média, por uma fracção do mesmo preço, os PCs ocuparam progressivamente o espaço das estações de trabalho Unix, as quais se viram progressivamente remetidas para nichos de mercado cada vez mais especializadas. Actualmente, a expressão estação de trabalho perdeu o seu significado original, sendo aplicada indistintamente a qualquer computador utilizado como posto de trabalho individual. A partir de 1996, marcas como a Intel, HP, IBM, Compaq e Novell compreendem as oportunidades oferecidas pelo Linux e investem no suporte deste sistema operativo, o que corresponde a uma certificação implı́cita da qualidade e fiabilidade atingidas pelo Linux. Actualmente (Agosto 2000) o Linux é, depois do Windows, o sistema operativo com maior número de utilizadores a nı́vel mundial e a mais forte alternativa aos sistemas operativos Windows e Windows NT, que dominam largamente o mercado. No entanto, apesar da sua maior fiabilidade e flexibilidade relativamente sistemas da Microsoft, é reconhecido que estes últimos apresentam uma interface com o utilizador mais simples que a apresentada pelo Linux. Apesar do esforço que tem sido feito para dotar o Linux de ferramentas semelhantes às existentes no Windows, a sua penetração tem vindo a ter lugar sobretudo no mercado de servidores, onde a fiabilidade é essencial e onde o utilizador/configurador directo é habitualmente um especialista em informática. De acordo com um estudo da IDC(csn, 2000) o Linux representa (números de 1999) apenas cerca de 2% a 4% do mercado dos postos de trabalho individuais, segmento de mercado que o Windows domina de forma esmagadora. A situação é distinta no mercado dos servidores, onde o Linux representou, em 1999, cerca de 25% do mercado, contra 38% do Windows NT da Microsoft. O restante mercado de servidores é repartido pelo NetWare da Novell (19%), outros Unix (15%) e outros sistemas (3%). Os números revelam também que o Linux tem sido o sistema operativo com maior crescimento no mercado dos servidores nos últimos anos, embora os ganhos observados se tenham vindo a verificar sobretudo à custa dos servidores Novell e Unix, enquanto que o Windows NT tem mantido uma fracção constante do mercado. Adicionalmente, tem-se assistido nos últimos anos à adopção do Linux em segmentos menos habituais, incluindo em controladores e dispositivos integrados (por exemplo, gravadores digitais de vı́deo) em que o núcelo do Linux é adoptado como base do sofwtare do sistema, embora a sua presença seja transparente para o utilizador. Apesar de uma relativa euforia que rodeia o sucesso do Linux nos últimos anos, poucos se arriscam a fazer previsões. Linus Torvalds mantem, ainda hoje, o controlo apertado do desenvolvimento do núcleo. Este é uma garantia de consistência exigida pelo mercado, mas os mais cépticos apontam para a dificuldade de Linus compatibilizar o papel cada vez mais mediático que tem vindo a assumir na divulgação do Linux com o tempo requerido pela crescente complexidade e dimensão do kernel. Por outro lado, à medida que o mercado cresce, aumenta também a pressão dos fabricantes para a adopção de caracterı́sticas e facilidades especı́ficas. Esta pressão comercial, além de representar uma variável nova no desenvolvimento do Linux, é olhada com C ÓPIA E DISTRIBUIÇ ÃO DE SOFTWARE : ASPECTOS LEGAIS E ACR ÓNIMOS IMPORTANTES 19 desconfiança por parte da comunidade de “linuxiana” que, durante anos, contribuı́u gratuitamente para o desenvolvimento do sistema operativo, receando-se que possa desmotivar alguns dos programadores mais activos. A possibilidade de grandes distribuidores de software e fabricantes de hardware poderem vir a dominar o desenvolvimento de um produto Open Source (V. secção 2.6) é um fenómeno novo e as suas consequências dificilmente previsı́veis. 2.6 Cópia e distribuição de software: aspectos legais e acrónimos importantes 2.6.1 Introdução Open source, free software, freeware, shareware, public domain e GPL são designações e acrónimos frequentes em informática, mas frequentemente mal entendidos. Nesta secção, introduzem-se alguns conceitos relativos às condições de cópia, distribuição e comercialização de software. Sublinhe-se que o tratamento rigoroso deste tema envolve aspectos complexos do ponto de vista legal e, frequentemente, polémicos. A abordagem que aqui se faz é meramente introdutória e, por este motivo, as definições aqui apresentadas não são completas do ponto de vista formal. Ao leitor mais interessado recomenda-se a consulta dos doscumentos disponı́veis sobre este tema http://www.gnu.org/. 2.6.2 Código binário e código fonte O código de um programa designa o conjunto de instruções que definem a sequência de operações a realizar pelo programa. Para a sequência, é no entanto importante entender a diferença entre código fonte e código objecto. O Código fonte de um programa designa o conjunto de ficheiros com instruções tal como escritos originalmente pelo programador. Estes ficheiros, escritos numa dada linguagem de programação, apresentam-se sob a forma de texto, de modo a que o seu conteúdo seja humanamente legı́vel. Desejávelmente, o código fonte de um programa inclui não apenas a sequência formal de instruções a executar, mas também anotações do programador (comentários), escritas em linguagem natural, que, embora não fazendo parte do programa, facilitam a sua compreensão e explicam aspectos particulares do seu funcionamento. O código fonte de um programa, embora sendo um formato conveniente para o programador humano, não é directamente executável pelo processador. Este só entende o chamdo código binário, um formato codificado em que as instruções são traduzidas em sequências de bits co- 20 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS nhecidas pelo processador e que, de um modo geral, diferem de fabricante para fabricante. Por exemplo, todos os ficheiros de DOS/Windows que contêm as extensões .com e .exe correspondem a programas em código binário, enquanto que ficheiros com a extensão .vbe correspondem a programas fonte escritos em Visual Basic. A transformação de código fonte para código binário é feita por um programa tradutor designado compilador, interpretador ou assemblador, consoante o caso. Este tópico será aprofundado na secção 4.2. Um programa disponibilizado em código fonte pode ser facilmente modificado por outro programador. O mesmo não sucede com o código binário, cuja alteração é geralmente muito mais complexa.15 2.6.3 Software proprietário Até à década de 1980, praticamente todo o software disponı́vel era produzido por fabricantes de hardware e software com fins comerciais. Este software, designado como proprietário, implica o pagamento de uma licença para ser utilizado e a cópia só é permitida para a criação de cópias de segurança (backup). A maioria do software proprietário é distribuı́da sob a forma closed source, ou seja, apenas em formato binário. Embora seja possı́vel para alguém experiente entender o código binário de programas simples, a mesma tarefa afigura-se extremamente difı́cil em programas de complexidade elevada. Por este motivo, a maioria das empresas que vendem código proprietário disponibilizamno em formato binário ou closed source, garantindo assim a exclusividade do domı́nio dos aspectos técnicos do programa. Deste modo, apenas a empresa vendedora do software detém a informação necessária para o corrigir e alterar, caso tal seja necessário. A maioria do software oriundo de companhias comerciais como a Microsoft, a Novell ou fabricantes de jogos é proprietário e, quase sempre, distribuı́do sob a forma closed source. A duplicação e cópia deste software sem autorização das empresas proprietárias dos dieitos é quase sempre ilegal, mesmo para uso doméstico e particular. Exceptuam-se situações particulares previstas nas próprias licenças, tal como a realização de cópias para efeitos de segurança (backup). Por outro lado, a aquisição de uma licença de um determinado programa apenas permite a sua instalação num único computador de cada vez. A instalação num segundo computador é geralmente legal desde que seja apagado do computador original. No caso de grandes empresas ou instituições de ensino, existem por vezes as chamada licenças de rede ou colectivas. Consoante as cláusulas particulares da licença, o detentor de uma destas 15 Embora tal não seja impossı́vel: a estratégia de propagação de muitos vı́rus inclui frequentemente a modificação de ficheiros binários. C ÓPIA E DISTRIBUIÇ ÃO DE SOFTWARE : ASPECTOS LEGAIS E ACR ÓNIMOS IMPORTANTES 21 licenças pode adquirir autorização para instalar um número ilimitado de cópias ou, alternativamente, para gerir de uma forma relativamente flexı́vel as licenças e cópias dentro da insituição. Noutra variante das licenças de rede, a instituição pode ter um número ilimtado de cópias instaladas, mas apenas um determinado número máximo de programas pode ser executado simultaneamente. Neste último caso, o número máximo de cópias em execução simultânea é monitorizado e autorizado por um programa especial, fornecida pelo fabricante, que supervisiona a rede de computadores da instituição. 2.6.4 Software livre, domı́nio público e GPL Em 1983, Richard Stallman, um investigador do MIT, inicia um movimento em defesa do free software ou software livre. Este movimento é concretizado no projecto GNU (ver secção 2.7), o qual tinha por objectivo o desenvolvimento de um sistema operativo compatı́vel com Unix, baseado exclusivamente em software livre. Por software livre entende-se software que se encontra publicamente disponı́vel em código fonte e que pode ser copiado, distribuı́do e alterado livremente. Além da defesa de um princı́pio essencial que Stallman designa por liberdade de programação16 , a principal motivação do projecto GNU foi a de fomentar a crı́tica, cooperação e intercâmbio entre a comunidade de programadores como forma de estimular a criação de mais e melhor sofwtare. Mais, porque a possibilidade de reutilizar livremente parte de programas já desenvolvidos e testados permite o densenvolvimento mais rápido de novas aplicações. Melhor, porque a possibilidade de qualquer programador consultar e modificar o código fonte permite que os erros detectados sejam mais rapidamente identificados e corrigidos. Apesar do seu nome, sofwtare livre não significa necessariamente software grátis. Uma empresa pode cobrar uma dada quantia por organizar e distribuir um CD-ROM com software livre, prestando eventualmente serviços complementares de assistência técnica. É, por exemplo, o caso da RedHat, actualmente a maior companhia de distribuição do sistema operativo Linux. O software distribuı́do nestas condições deverá, no entanto, manter-se livre, no sentido em que qualquer utilizador tem o direito de duplicar o CD e de modificar o código ali incluı́do. O conceito de software livre é frequentemente confundido com a noção de software de domı́nio público ou (public domain). Os dois referem, no entanto, situações legais diferentes. Quando alguém coloca um programa (ou produto) no domı́nio público, não retém qualquer direito de autor (copyright) sobre o material publicado. Tal significa que qualquer indivı́duo ou empresa tem o direito de modificar o software e eventualmente comercializá-lo sob a forma de programa proprietário. O autor original do programa nada pode fazer porque, ao colocar o produto 16 Richard Stallman produziu muitos artigos em que discute diversos aspectos da filosofia GNU, os quais podem ser consultados em http://www.gnu.org/. 22 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS no domı́nio público, prescindiu de todos os direitos legais que sobre ele poderia deter. Por este motivo, esta forma de distribuição não é encorajada pelos defensores do free software. Distribuir um programa como software livre não significa que o programador prescinda ou ceda os direitos de autor. Este facto permite que o autor, embora sem limitar o direito de cópia e modificação por terceiros, possa colocar limitações à forma como este programa é utilizado ou redistribuı́do por terceiros. Para clarificar este aspecto, o conceito de software livre segundo a GNU foi formalizado na chamda Gnu Public Licence (GPL), que define um conjunto de condições que devem ser respeitadas por qualquer utilizador de software GNU. Basicamente, a GPL estabelece que o autor original do software retem os seus direitos iniciais e que a redistribuição de versões originais ou modificadas só é permitida quando acompanhadas do código fonte correspondente e sob as mesmas condições da distribuição original. Quando uma versão modificada é distribuı́da, deve estar explı́cito no código fonte que se trata de uma versão alterada, devendo as modificações estar claramente identificadas. Quem modifica o software retém, por sua vez, o direito de autor sobre as partes que modificou ou acrescentou. A licença GPL não se destina a utilização interna do projecto GNU, podendo ser adoptada por qualquer programador que deseje distribuir software nos termos definidos pela GPL. Frequentemente a designação open software é utilizada alternativamente a free software. Embora em muitas situações práticas estas duas designações sejam equivalentes, estritamente falando open source apenas identifica que o software é disponibilizado em código fonte. Embora não seja frequente, esta designação pode abranger software que não seja disponibilizado gratuitamente e que a sua duplicação seja proı́bida. Além da versão GPL, há diversas variantes de licenças de distribuição de software livre, cada uma com as suas subtilezas legais. No seus detalhes, a GPL é geralmente considerada a mais “fundamentalista” em termos de free software. Existem licenças de software livre que permitem, apesar de tudo, o desenvolvimento e a comercialização de produtos ou versões modificadas em formato closed-source, ou em que a redistribuição da versão original é livre mas não a redistribuição de versões modificadas. 2.6.5 Freeware e shareware Freeware e shareware designam formas de distribuição de software em formato closed source e, como tal não modificáveis. O software é para, efeitos legais, proprietário do autor. De um modo geral, designa-se por freeware software de cópia e distribuição gratuita, mas que é disponibilizado apenas em formato binário e, como tal, não modificável. Deste modo, o freeware é gratuito, mas não é livre no sentido definido pela GNU e pela GPL. Shareware é uma forma de distribuição que foi popularizada pela internet e que surge como O PROJECTO GNU E O SISTEMA GNU/L INUX 23 forma de comercialização alternativa de software proprietário por parte de programadores individuais e pequenas empresas. De forma a evitar o recurso a canais de distribuição comerciais convencionais, que implicam um esforço financeiro e de marketing adicionais, a distribuição de shareware baseia-se na autorização de cópia e distribuição livre por parte dos utilizadores. Pretendese, desta forma, facilitar tanto quanto possı́vel a divulgação do programa distribuı́do. No entanto, os utilizadores são supostos procederem ao registo da sua cópia e pagamento de uma licença se, após um perı́odo de teste do programa, optarem pela sua utilização permanente. Frequentemente, os programas distribuı́dos em shareware descrevem as condições e limitações da versão de teste e, por vezes, contêm dispositivos que bloqueiam o seu funcionamento após um detrminado perı́odo de tempo sem registo ou que limitam as sua funcionalidades. Embora as disposições legais do shareware sejam frequentemente ignoradas, do ponto de vista legal, a utilização de shareware após o perı́odo experimental é equivalente à utilização ilegal de software proprietário. 2.7 O projecto GNU e o sistema GNU/Linux Conforme se referiu anteriormente, em 1983 Richard Stallman deu inı́cio ao projecto GNU, o qual tinha por objectivo o desenvolvimento de um sistema operativo compatı́vel com Unix, que representasse eventualmente uma evolução deste, baseado exclusivamente em software livre. A designação GNU é um acrónimo proposto por Stallman derivado de “GNU’s not Unix”, definição em que a recursividade surge como um tributo a um conceito importante para a ciência da computação. O projecto GNU tinha como objectivo o desenvolvimento de um sistema operativo completo. Neste contexto, é importante detalhar o significado de completo: além do núcleo, que gere a distribuição de recursos fı́sicos pelos programas e a comunicação entre estes, um sistema operativo requer um conjunto grande de programas utilitários. Duplicar, apagar ou editar ficheiros, compilar, gerir contas de utilizadores e espaço em disco, estabelecer ligações com outros computadores, arquivar e até dialogar com um utilizador através de uma linha de comando são tarefas que não são executadas directamente pelo núcleo, mas sim por um vasto conjunto de pequenas aplicações que são geralmente fornecidas conjuntamente com o sistema operativo. Por exemplo, programas como o “notepad” e o “explorer” são essenciais numa distribuição do Windows, mas do ponto de vista funcional são independentes do núcleo do Windows. Face à complexidade do desenho do núcleo de um sistema operativo, durante vários anos o projecto GNU dedicou-se apenas ao desenvolvimento de utilitários que constituiam versões melhoradas da maioria das ferramentas do Unix da ATT. Além da contribuição do próprio Stallman, que incluı́u algumas componentes fundamentais como as versões originais do compilador gcc, do editor emacs, do gerador de parsers bison, participaram no projecto centenas de programadores. No inı́cio da década de 90, o projecto GNU já incluı́a versões de praticamente todas as ferramentas 24 U NIX , GNU/L INUX E OUTROS ACR ÓNIMOS do sistema Unix, faltando apenas o desenvolvimento do núcleo. Stallman pensava desenvolver o núcleo do GNU baseado no Mach, um sistema operativo que, tal como o Minix de Tanenbaum, se baseava numa arquitectura de microkernel, mas o projecto enfrentava dificuldades várias. A decisão de Linus de desenvolver o Linux e o distribuir sob a licença GPL só foi possı́vel pela existência prévia de todos os utilitários da GNU necessários para preencher o espaço que medeia entre o núcleo e o utilizador. Estritamente falando, Linux designa apenas o núcleo do sistema operativo. Se é verdade que o sucesso do Linux só é possı́vel pela existência prévia do projecto GNU, é também um facto que é o trabalho de Linus que permite dotar, pela primeira vez, o projecto GNU de um núcleo estável e, assim, fechar o circulo iniciado e projectado por Richard Stallman em 1983. Num sistema Linux tal como distribuı́do actualmente por empresas como a RedHat ou a Debbian, cerca de 30% do código fonte é tem origem no projecto GNU e apenas 3% a 5% representa o núcleo do sistema operativo17 . Por este motivo, Richard Stallman defende que a designação correcta para os sistemas Linux deveria ser sistema GNU/Linux e não apenas Linux, de forma a substanciar o papel que o projecto GNU teve e tem na génese e manutenção do Linux. 17 O restante software é também gratuito, mas nem sempre distribuı́do sob a licença GPL (é o caso, por exemplo da versão XFree86 do sistema X Windows). Capı́tulo 3 Ambiente de trabalho em Unix 3.1 Introdução Neste capı́tulo faz-se uma sintese dos principais comandos do sistema Unix e de alguns aspectos do seu funcionamento. Pretende-se aqui descrever apenas os comandos essenciais a uma primeira interacção com o sistema, sem aprofundar os seus detalhes de funcionamento. Supõe-se que aprendizagem do comando <man> e a consulta de outros elementos de estudo (ver capı́tulo 6) serão os complementos deste texto introdutório. Conforme se referiu no capı́tulo 2, o GNU/Linux não é mais do que uma implementação de Unix em software livre. Deste modo, no seguimento utilizar-se-á a designação “Unix” a propósito de comandos e conceitos genéricos, restringindo-se uso da designação “Linux” a exemplos e situações que digam respeito esepcificamente a esta implementação do Unix. 3.2 3.2.1 Acesso ao sistema Conta de utilizador O sistema UNIX é um sistema multi-utilizador, capaz de gerir o acesso simultâneo de diversos utilizadores e aplicações a uma mesma máquina. Cada utilizador é identificado perante a máquina pela especificação de um dado username, atribuı́do pelo gestor do sistema. O username permite a manutenção de um registo (account, ou conta de utilizador) individual das operações efectuadas e recursos utilizados. Cada utilizador é responsável perante o gestor da máquina por todas as utilizações indevidas ou ilegais dos recursos disponibilizados que sejam registados na sua conta individual. 26 A MBIENTE DE TRABALHO EM U NIX De modo a garantir a confidencialidade e segurança do acesso a cada conta de utilizador, a cada username encontra-se associada uma password especı́fica. A password é atribuı́da inicialmente pelo gestor do sistema, mas pode ser alterada em qualquer altura pelo próprio utilizador (o comando a utilizar para este efeito é descrito numa secção seguinte). A password tem uma dimensão máxima de 8 caracteres podendo incluir a maioria dos caracteres disponı́veis nos teclados. Dada a existência de programas capazes de descodificar passwords com estruturas simples, a escolha de uma password deve obedecer aos seguintes critérios: • Ter uma dimensão mı́nima de 6 caracteres. • Não corresponder, em nenhum caso, a uma palavra simples ou nome próprio de qualquer lı́ngua. • Incluir caracteres minúsculos e maiúsculos. • Incluir alguns dı́gitos e pelo menos 1 caracter não alfanumérico (p. ex., &, *, !, etc.) na sua composição. 3.2.2 Login e Shell O acesso a uma sessão de trabalho em UNIX efectua-se especificando o username (solicitado normalmente pela indicação login:) e password solicitados pelo sistema. A especificação quer do username quer da password deve ser seguida da tecla <return>. Por razões de confidencialidade, a password não surge no monitor quando é introduzida. Após a entrada em sessão, o utilizador passa a dialogar com um interpretador de comandos de UNIX, vulgarmente designado por shell. Existem diversos interpretadores de comandos de UNIX com caracterı́sticas distintas (bash, cshell, tcshell, bourne, etc). A discussão das caracterı́sticas que distinguem as diversas shells encontra-se fora do âmbito deste texto. No seguimento, assumirse-á que o utilizador trabalha com a bash, a qual é a shell por omissão dos sistemas Linux. Note-se, no entanto, que os comandos mais correntes de UNIX correspondem a aplicações independentes do interpretador de comandos, e como tal disponı́veis em qualquer shell. No final da sessão de trabalho, o utilizador deverá desligar a sua sessão pela execução do comando logout. A verificação de que a sessão foi desligada é essencial para garantir a segurança do sistema e evitar a utilização indevida da sua conta de utilizador. No sistema Unix, cada programa tem geralmente associado um conjunto de variáveis que contêm informação sobre o ambiente e que podem ser consultadas em qualquer altura. Algumas destas variáveis são inicializadas pelo sistema, enquanto que outras podem ser definidas pelo utilizador no ficheiro .bashrc do seu directório principal, o qual é lido sempre se inicia o interpretador O SISTEMA DE JANELAS X 27 de comando bash. Por exemplo, a variável PATH, especifica a lista de directórios consultados pela shell para procurar um programa que se pretenda executar, separados por doispontos. A consulta desta variável pode ser feita pelo comando $ echo $PATH 3.3 O sistema de janelas X O sistema de janelas X é a interface gráfica adoptada em máquinas com o sistema Unix. Quando o utilizador efectua o login no sistema de janelas X, passa a poder abrir diversas janelas simultaneamente no écran. Assim, uma janela poderá incluir um gestor de ficheiro, outra pode corresponder a um terminal virtual onde é executada uma shell e outra a um editor de texto. Com o login, é normalmente executado automaticamente um programa designado gestor de janelas (window manager), responsável pelo controlo das diversas janelas e pela gestão dos menus de utilizador, geralmente acessı́veis posicionando o rato em qualquer ponto do fundo do écran e carregando no botão do lado direito. No entanto, embora o sistema X seja o mesmo, existem hoje em dia diferentes gestores de janelas e interfaces de utilizador, com aspectos gráficos muito distintos e configuráveis através de temas, skins e outras opções do utilizador. Este facto gera uma grande variabilidade nas interfaces possı́veis, fazendo a sua descrição cair fora do âmbito deste texto. Sublinhe-se apenas que existem vários programas que permitem abrir um terminal virtual no sistema de janelas X, entre os quais o xterm, o nxterm ou o gnome-terminal. Um terminal virtual executa uma shell, a qual funciona em modo de comando de forma idêntica ao que sucede em modo de texto. Grande parte da descrição das próximas secções admitem que o utilizador dialoga com o sistema, através de uma shell, em modo de comando. No sistema X, é possı́vel executar um programa num computador e a janela gráfica correspondente ser aberta no monitor ligado a outra máquina. Esta possibilidade é controlada, nos programas que usam X, através da variável de ambiente DISPLAY. Uma inicialização incorrecta desta variável é suficiente para impedir o funcionamento correcto do sistema gráfico. Embora esta variável seja inicializada automaticamente de forma a apontar para o écran em que se está a trabalhar, é possı́vel alterá-la com o comando $ export DISPLAY=<nome>:0 onde <nome> é o nome do computador em cujo sistema gráfico se pretende abrir a janela. Para que isto seja possı́vel é necessário que este último autorize a ligação. Esta autorização que pode 28 A MBIENTE DE TRABALHO EM U NIX ser dada através dos comandos xhost ou xauth. 3.4 3.4.1 Modo interactivo Hierarquia de directórios Um ficheiro corresponde a um conjunto estruturado de dados residente na memória secundária (disco) do sistema. O conteúdo de um ficheiro pode ser texto (como o deste manual), um programa executável, dados, etc. Os ficheiros em UNIX encontram-se organizados por directórios (ou directorias). Um directório pode ser comparado a um arquivo em que são guardados ficheiros relativos a um tema comum. No entanto, cada directório pode incluir, além de ficheiros, outros directórios, não existindo um limite pré-estabelecido para o número de nı́veis que esta estrutura hierárquica pode suportar. Na figura 3.1 apresenta-se um exemplo tı́pico de uma árvore de directórios em UNIX. Nesta figura, os rectângulos a cheio representam ficheiros e os restantes directórios. Nos sistemas UNIX, um directório não é mais que um caso particular de um ficheiro com funcionalidades especı́ficas. Frequentemente, um mesmo comando pode ser aplicado igualmente a um ficheiro ou a um directório, embora o seu modo exacto de funcionamento possa ser ligeiramente diferente num caso e outro. Em geral, cada utilizador tem associado à sua conta um directório de defeito (home directory) que pode gerir da maneira que considerar mais conveniente. A partir da sua home directory, o utilizador pode criar um número arbitrário de nı́veis de directórios (em nı́veis hierarquicamente inferiores), sendo apenas limitado pelo espaço disponı́vel em disco (ou pelo espaço em disco associado à sua conta de utilizador). Como é evidente, é conveniente o utilizador definir os seus directórios de acordo com as diferentes trabalhos que realiza no sistema, embora este procedimento não seja obrigatório. A cada ficheiro de UNIX encontra-se associado um nome (filename). O nome de um ficheiro é composto de 1 a 14 caracteres (embora muitas versões de UNIX admitam nomes mais longos). Apesar de ser possı́vel utilizar quase todos os caracteres disponı́veis no nome de um ficheiro, é por diferentes motivos conveniente restringir os nomes de ficheiros a caracteres alfanuméricos (números e letras) e aos caracteres ’.’ e ’ ’. Como é evidente, todos os ficheiros residentes num mesmo directório têm um nomes distintos; no entanto, é possı́vel haver ficheiros com nomes idênticos em directórios diferentes. Todos os directórios do sistema UNIX são definidos a partir de um directório de nı́vel superior. A única excepção a esta regra é o directório raı́z do sistema (root directory) o qual é criado durante M ODO INTERACTIVO 29 Figura 3.1: Exemplo de uma árvore de directórios em UNIX. 30 A MBIENTE DE TRABALHO EM U NIX o processo de instalação do sistema na máquina. No caso do exemplo da figura 3.1, o directório raı́z surge no topo da hierarquia, sendo referenciado pela barra (/). Todos os directórios existentes no sistema de ficheiros ”descendem”em última análise deste, embora seja variável o número de nı́veis da hierarquia existente entre ambos. Cada ficheiro ou directório é registado em nome de um dado utilizador. O sistema mantem, paralelamente, um mecanismo de controlo de acessos a cada ficheiro ou directório. A permissão de acesso a um dado ficheiro pode ser definida em 3 nı́veis distintos: utilizador proprietário do ficheiro (owner), grupo (group) e todos os outros utilizadores (world). A definição de grupos de utilizadores permite a que utilizadores de um mesmo grupo partilhem ficheiros de interesse comum. Para cada um deste nı́veis, é possı́vel definir o ficheiro como de leitura (r), escrita (w), execução (x) ou qualquer combinação dos três modos anteriores. A permissão de acessos a dado ficheiro pode ser alterado em, qualquer altura pelo proprietário do ficheiro com o comando chmod. 3.4.2 Pathnames Absolutos Durante a execução de uma tarefa especı́fica no sistema, o utilizador encontra-se localizado num directório bem determinado (directório de trabalho). Quando um ficheiro é especificado pelo seu nome simples, admite-se que este directório reside (ou deve ser criado, se for este o caso) no directório de trabalho. É no entanto possı́vel especificar um ficheiro residente em outro directório pela indicação do pathname absoluto do ficheiro. O pathname absoluto de um ficheiro é constituı́do pelo seu nome precedido pelo nome de todos os directórios de que ele depende até ao directório raı́z, separadas por uma ’/’1 . Considere-se por exemplo o ficheiro prog.c residente no nı́vel mais baixo da hierarquia representada na fig. 3.1. O pathname absoluto deste ficheiro é /home/user1/prog1/src/prog.c Na definição de um pathname absoluto pode ser usado o sı́mbolo ˜ (til) para referenciar o directório de defeito de um dado utilizador. Por exemplo,˜<username> referencia o directório de defeito do utilizador <username>. Caso o nome de utilizador seja omitido,˜referencia o directório de defeito do utilizador que usa o comando. Por exemplo, no caso da figura 3.1, admitindo que a área de defeito do utilizador user1 é /home/user1 1 Quem estiver familiarizado com o sistema MS-DOS, facilmente reconhecerá a semelhança entre a hierarquia de ficheiros nos dois sistemas, substituindo a barra invertida (backslash) por /. É conveniente ainda notar a ausência em UNIX do conceito de drive do MS-DOS. M ODO INTERACTIVO 31 e do utilizador user2 /home/user2 o utilizador user2 pode aceder a prog.c (se tiver permissão de acesso a este ficheiro) explicitando ˜user1/prog1/src/prog.c enquanto que utilizador user1 poderá obter o mesmo resultado referenciando ˜/prog1/src/prog.c 3.4.3 Pathnames relativos Conforme se viu na secção anterior, a especificação de um pathname absoluto começa com uma ’/’, que indica o directório raı́z do sistema. Se esta barra inicial for omitida na especificação do pathname, este é considerado como relativo ao directório de trabalho. Deste modo, se o directório de trabalho fôr /home/user1 é possı́vel aceder directamente a prog.c especificando prog1/src/prog.c Quando um directório é criado, são automaticamente criadas dois ficheiros que têm funções especı́ficas. O primeiro destes ficheiros é identificado por um único ponto (’.’) e identifica o próprio directório. O segundo ficheiro é identificado por dois pontos (’..’) e identifica o directório de nı́vel hierárquico imediatamente superior, i.e., o directório de que este descende. Este último ficheiro pode ser usado para especificar um pathname relativo de um ficheiro residente num nı́vel superior da hierarquia ou num ramo diferente. Admita-se por exemplo que o directório de trabalho é /home/user1/prog1/src/sub1 é possı́vel aceder directamente a prog.c especificando ../prog.c 32 A MBIENTE DE TRABALHO EM U NIX De modo semelhante, caso o directório de trabalho seja /home/user2/prog/src é possı́vel aceder directamente a prog.c especificando ../../../user1/prog1/src/prog.c 3.5 Comandos O utilizador dialoga com a shell pela introdução de comandos. Um comando é normalmente especificado por uma linha de texto seguida da tecla <return>2 . Após a execução de cada comando, surge no monitor o prompt do interpretador, indicando que este está pronto a receber uma nova linha de comando. O prompt de defeito da shell é o caracter $, embora este possa ser redefinido pelo utilizador. Um comando em UNIX tem habitualmente a forma3 $ <nome do comando> <flags> <argumentos> As <flags> são geralmente opcionais e especı́ficas de cada comando. Têm normalmente a forma de um hı́fen ’-’ seguido de uma letra. São geralmente utilizadas para especificar determinadas funcionalidades não disponı́veis na versão base do comando. Os <argumentos> são igualmente depedentes do comando, e designam habitualmente entidades sobre as quais o comando opera. Embora esteja fora do âmbito deste texto uma descrição dos comandos disponı́veis em UNIX, inclui-se aqui uma breve listagem dos utilizados mais frequentemente. A descrição apresentada é muito sumária, devendo o utilizador usar o comando man para consulta a uma descrição mais detalhada de cada comando. • man <comando> Lista a página de manual de <comando> e tem as funcionalidades associadas ao help existente em outros sistemas operativos. De um modo geral, a página de manual inclui 2 É possı́vel utilizar comandos com mais de uma linha de texto; no entanto este caso não será aqui considerado. Nos exemplos de comandos incluı́dos neste texto, faz-se preceder o comando do sı́mbolo $, caracterı́stico do prompt da shell. Convém notar no entanto que este sı́mbolo não é introduzido pelo utilizador. 3 C OMANDOS 33 uma descrição sumária das funcionalidades do comando e das suas opções. As páginas de manual de Unix são, de um modo geral, sistemáticas e sintéticas. Embora o seu formato tı́pico possa parecer hermético nas primeiras consultas, o mesmo revela-se extremamente eficiente após um primeiro perı́odo de habituação à terminologia utilizada. • pwd Indica o directório de trabalho corrente. • ls Lista os ficheiros existentes no directório de trabalho. É possı́vel acrescentar argumentos de forma a selecionar apenas ficheiros com determinadas caracterı́sticas: por exmplo, ls a* lista todos os ficheiros começados por a, enquanto que ls a*f*b ghi* lista todos os ficheiros cujo nomes tenha, inı́cio em a, fim em b e apresentem um f pelo meio, além de todos os ficheiros iniciados por ghi. • cd <nome> Muda o directório de trabalho corrente para o directório <nome>. Se <nome> não for indicado, muda o directório corrente para a home directory do utilizador. • mkdir <nome> Cria o directório <nome> • cp <origem> <destino> Copia o ficheiro <origem> para <destino>. Se <destino> fôr um directório, é criado um ficheiro com o nome <origem> neste directório. • mv <origem> <destino> Muda o nome do ficheiro ou directório <origem> para <destino>. Se <destino> fôr um nome de um directório já existente, o ficheiro ou directório <origem> é deslocado para o directório <destino>, mantendo o mesmo nome. • rm <nome> Apaga o ficheiro <nome>. • rmdir <nome> Apaga o directório <nome>. 34 A MBIENTE DE TRABALHO EM U NIX • cat <nome> Lista o ficheiro <nome>. Para visualização do conteúdo de um ficheiro, este comando é geralmente substituido pelo comando <less>, descrito mais à frente. • du -s <nome> Indica o espaço em disco ocupado pelo ficheiro <nome>. Caso <nome> seja um directório, o espaço indicado inclui todos os seus ficheiros e sub-directórios. Para saber a área total ocupada pelo utilizador usar du -s . • less <nome> Lista o ficheiro <nome> página a página. O avanço de cada página é realizado pela utilização da tecla de espaço. O comando pode ser terminado em qualquer altura com a tecla q. • chmod <modo> <nome> Muda a permissão de acessos do ficheiro <nome> de acordo com <modo>. • grep <sequencia><nome> Lista todas as linhas do ficheiro <nome> que contenham a sequência de caracteres <sequencia>. • passwd Altera a password do utilizador. • logout Sair de sessão. Um comando pode ser interrompido premindo simultaneamente as teclas <ctrl> e c. 3.6 Dispositivos de entrada e saı́da Os dispositivos de entrada e saı́da são tratados no sistema UNIX como ficheiros de caracterı́sticas especiais (special files). A cada dispositivo de entrada/saı́da está geralmente associado um ficheiro do directório /dev. Por exemplo, a escrita ou leitura do terminal de trabalho (seja ele real ou uma janela virtual) pode ser escrevendo ou lendo o ficheiro /dev/tty. Este tipo de organização permite uma flexibilidade muito grande no desenvolvimento e utilização de aplicações. R EDIRECCIONAMENTO 35 3.7 Redireccionamento A todas as aplicações de UNIX são automaticamente associados dois dispositivos de saı́da e um de entrada: • standard output Dispositivo de defeito para saı́da de mensagens. No caso de uma sessão no terminal, este dispositivo é, por defeito, o monitor do terminal • standard error Dispositivo de defeito para saı́da de mensagens de erro. No caso de uma sessão no terminal, este dispositivo é, por defeito, o monitor do terminal. • standard input Dispositivo de defeito de entrada de dados. No caso de uma sessão no terminal, este dispositivo é, por defeito, o teclado do terminal. Em qualquer dos casos (teclado/monitor), estes dispositivos correspondem ao ficheiro especial /dev/tty. Frequentemente, é conveniente alterar um ou mais dos dispositivo de defeito anteriormente indicados. A especificação de um dispositivo entrada/saı́da alternativo pode ser efectuado na linha de comando. A especificação de um dispositivo alternativa como standard output efectua-se adicionando à linha do comando o sı́mbolo > seguido do nome do dispositivo pretendido: $ <comando> <flags e argumentos> > <dispositivo de saı́da> Considere-se, por exemplo, o caso do comando ls. Como descrito anteriormente, este comando lista os ficheiros de um dado directório. Por defeito, este comando produz uma listagem no terminal (standard output). Se se pretendar criar um ficheiro de nome lista no directório de trabalho com o resultado da listagem, o comando a utilizar é $ ls > lista Se pretender redireccionar conjuntamente o standard output e standard error para um mesmo ficheiro, pode ser usada a seguinte linha de comando: $ <comando> <flags e argumentos> >& <dispositivo de saı́da> De igual modo, é possı́vel redireccionar o dispositivo de entrada standard input adicionando à linha do comando o sı́mbolo < seguido do nome do dispositivo pretendido: $ <comando> <flags e argumentos> < <dispositivo de entrada> 36 A MBIENTE DE TRABALHO EM U NIX 3.8 Pipes O UNIX possibilita que o dispositivo de standard output de uma aplicação seja ligado directamente ao dispositivo de standard input de uma segunda aplicação pela utilização do mecanismo de pipe. Este resultado é obtido indicando as duas aplicações em sequência na mesma linha de comando, separados pelo caracter |. Este mecanismo é equivalente a redireccionar a saı́da da primeira aplicação para um ficheiro, e utilizar o ficheiro assim criado como entrada da segunda aplicação. Recorrendo ao exemplo já dado anteriormente, admita-se que se redirecciona a listagem do directório corrente para um ficheiro lista, e posteriormente se pretende visualizar o conteúdo do ficheiro com o comando less. Este procedimento pode ser realizado pela sequência de dois comandos: $ ls > lista $ less lista Exactamente mesmo resultado pode ser obtido, sem a criação do ficheiro lista, pela utilização de um pipe em que a saı́da do comando ls é automaticamente utilizada como entrada do comando less. $ ls | less Note-se que a utilização de pipes, além de facilitar a especificação de comandos estruturados complexos, é extremamente eficiente dado não implicar a criação de ficheiros temporários intermédios (toda a comunicação entre aplicações é efectivamente realizada na memória central da máquina). Capı́tulo 4 Desenvolvimento de programas 4.1 Introdução O desenvolvimento de programas em linguagens de alto nı́vel requer um processo de desenvolvimento, teste e aperfeiçoamento que, na maioria dos casos, tem que ser repetido diversas vezes diversas vezes até se atingir uma versão funcional e estável. Grande parte do software comercial é sujeito a revisões, melhoramentos e correcções de erros mesmo depois da primeira versão ser comercializada. O processo iterativo de desenvolvimento e teste de um programa é designado por ciclo de desenvolvimento de um programa, e o seu entendimento é fundamental para a compreensão dos diversos componentes que envolvem od desenvolvimento de um programa numa linguagem de alto nı́vel. 4.2 Assembly e Linguagens de alto nı́vel As instruções executáveis directamente por um dado processador têm uma estrutura relativamente simples e variam consoante o modelo e o fabricante. Estas instruções têm formatos relativamente simples e uma ligação próxima ao hardware, designando-se por isso código máquina do processador. Uma determinada instrução em código máquina pode ter como significado “lê o conteúdo do endereço de memória 1000 e coloca-o no registo A” ou “testa o conteúdo do registo B e, se for zero, executa as intruções que se encontram a partir do endereço 21456”. A linguagem de programação Assembly permite programar em código fonte (ou seja, em formato de texto) mas usando uma linguagem muito semelhante à do processador. A tradução de Assembly para código binária é feita por um programa designado Assemblador. 38 D ESENVOLVIMENTO DE PROGRAMAS Dada a sua proximidade ao hardware, a linguagem Assembly é conveniente para explorar as potencialidades do processador, mas muito pouco prática para desenvolver estruturas lógicas mais elaboradas1 . Deste modo, os programas são geralmente desenvolvidos numa linguagem de alto nı́vel, em que as instruções especificam operações entre entidades lógicas e funcionais abstractas e independentes do processador. Por exemplo, a sequência de instruções em C if ( a == b) x += 5; else y = x + 3; tem um significado próximo do que é de esperar da sua leitura em inglês natural: “compara o valor das variáveis a e b e, se forem iguais, incrementa a variável x de 5 unidades, senão atribui à variável y o resultado da adição de x com 5”. Existem diversas linguagens de alto nı́vel, como por exemplo o C, o C++, o Pascal, o Java, o Lisp, o Fortran e o Basic, entre outras. Além da maior comodidade de programação, o desenvolvimento de programas em linguagens de alto nı́vel garante que o código desenvolvido seja independente do processador. A tradução de um programa de alto nı́vel para linguagem máquina é realizada por um programa designado por compilador. Assim, quando um fabricante desenvolve um novo processador, é suficiente escrever um compilador para uma dada linguagem de alto nı́vel2 para que o software existente nessa linguagem possa ser executado no novo processador. O C, o C++, o Pascal e o Fortran são exemplo de linguagens de alto nı́vel compiladas. Nestes casos, o programa é trazudido e só então executado. Alternativamente, existem linguagens que interpretadas: o programa é lido por um interpretador, que lê o código de alto nı́vel e procede simultaneamente à execução das instruções correspondentes de baixo nı́vel. São exemplo de linguagens interpretadas o Basic e certos formatos de Java e Lisp. A execução de um programa compilado é geralmente mais rápida do que a de um programa interpretado, já que neste último caso o interpretador procede simultaneamente à tradução e à execução do código fonte. Por outro lado, a inexistência de um passo de compilação explı́cito nas linguagens interpretadas simplifica a fase de desenvolvimento e teste de um programa. 1 No entanto, a utilização de Assembly foi uma prática generalizada para a escrita de compiladores e sistemas operativos até à década de 80. 2 Na maioria dos casos, não é necessário re-escrever a totalidade do compilador, sendo suficiente a adaptação de um já existente. C ICLO DE DESENVOLVIMENTO 39 4.3 4.3.1 Ciclo de desenvolvimento Compilação e “linkagem” O ciclo de desenvolvimento de um programa numa linguagem de alto nı́vel compilada encontra-se esquematizado na figura 4.1, onde os sufixos dos ficheiros correspondem ao desenvolvimento de um programa C em Unix. A primeira etapa do desenvolvimento envolve a escrita de um ficheiro de texto (ficheiro ou código fonte) com as instruções do programa, utilizando um determinado editor de texto. Existem diversos editores de texto disponı́veis em Linux, semdo todos eles adequados à escrita de programas (ver capı́tulo 5). O nome do ficheiro fonte é arbitrário, devendo ser escolhido pelo programador de modo a ser sugestivo da função realizada pelo programa. Além do nome do propriamente dito, o sufixo ou extensão do ficheiro deve especificar a linguagem de linguagem de programação adoptada: xpto.c para um programa desenvolvido em C, xpto.cc para o C++, xpto.f para o Fortran ou xpto.p para o Pascal. Após esta etapa, o ficheiro fonte é traduzido para o chamado código objecto através do compilador. Em Linux, a compilação de um programa escrito em C é realizada pelo compilador gcc. Assim, admitindo que o código fonte reside no ficheiro xpto.c, a compilação efectua-se executando o comando $ gcc -ansi -pedantic -Wall -c xpto.c As opções “-ansi -pedantic” indicam ao compilador que só deve aceitar código C-ansi e a opção “-Wall” que deverá reportar todas as situações potencialmente incorrectas que sejam detectáveis. A opção “-c” indica que se pretende apenas compilar o ficheiro fonte. Como resultado deste comando é criado um ficheiro xpto.o com o chamado código objecto. O sufixo dos ficheiros do código objecto é .o em Unix e .obj em DOS/Windows. O código objecto é um formato binário, em que as instruções do ficheiro fonte se encontram já traduzidas em código máquina. No entanto, o ficheiro assim obtido não é ainda um programa executável porque se encontra geralmente incompleto: a criação de um programa executável exige normalmente que sejam reunidos ao código objecto módulos pré-compilados no sistema sob a forma de bibliotecas, os quais são responsáveis pela execução de funções que são idênticas para vários programas. É o caso, por exemplo, de módulos para a realização de operações de leitura e escrita de dados ou para o cálculo de funções trigonométricas. A geração do programa executável realiza-se atravé do chamado linker, designação que não 40 D ESENVOLVIMENTO DE PROGRAMAS Figura 4.1: Ciclo de desenvolvimento de um programa. C ICLO DE DESENVOLVIMENTO 41 tem ainda uma tradução bem aceite em Português. Por este motivo, é frequente designar por “linkagem” a operação realizada pelo linker, embora se trate obviamente de um aportuguesamento forçado3 . A “linkagem” de um programa em Unix pode ser realizada pelo comando $ gcc xpto.o operação que dá origem a um ficheiro designado a.out com o código executável. Sublinhe-se que embora a compilação e o “linker” sejam invocados pela execução do mesmo comando (gcc), este verifica qual a operação a realizar pela análise do sufixo dos ficheiros envolvidos e, caso se trate de um ficheiro objecto, este é automaticamente passado ao linker (programa ld em Unix). A vantagem de este ser invocado através do gcc é a junção automática ao processo de “linkagem” das bibliotecas pré-compiladas da linguagem C que, de outra forma, teriam que ser especificadas pelo utilizador. No comando de “linkagem” simples é possı́vel gerar um ficheiro executável com um nome alternativo a a.out. Assim, o comando $ gcc xpto.o -o xpto especifica que o nome do executável deverá ser xpto. Por outro lado, as fases de compilação e “linkagem” podem ser chamadas conjuntamente com o comando $ gcc -ansi -pedantic -Wall xpto.c -o xpto mas deve manter-se presente que este comando realiza as duas operações (compilação e “linkagem”) em sequência. A execução do programa executável tem lugar por um comando com o nome do ficheiro executável ou seja $ a.out ou $ xpto consoante o caso. 3 As traduções literais “ligador” e “ligação”, apesar de serem termos sugestivos da operação realizada, não são correntes em Português. 42 D ESENVOLVIMENTO DE PROGRAMAS 4.3.2 Erros sintáticos e semânticos Considere-se que se pretende escrever um programa em C para cálculo do dobro do coseno de um número e que, para este efeito, se cria um ficheiro “dobro.c” com o seguinte conteúdo’: /* *FILE * dobro.c * *CONTENTS * Programa que calcula o dobro do coseno de um numero * *CREATOR/CONTACT Fernando Mira da Silva, IST ([email protected]) * * */ #include <stdio.h> #include <math.h> int main(){ /* Declaração de variáveis */ float x,y; /* Bloco de instruções */ printf(" Introduza o argumento: "); scanf("%f",&x); y = 3.0 * cos(x0); printf(" O dobro do coseno de %f é %f \n",x,y) exit(0); } A primeira parte deste programa, demarcada pelos caracters /* e */, corresponde à zona de comentários. A directiva “#include <stdio.h>” é necessária porque o programa utiliza operações de entrada e saı́da e “#include <math.h>” porque é utilizada uma função matemática (coseno). O corpo do programa encontra-se entre as chavetas que se seguem a main(). float x,y; indica que o programa utiliza duas variáveis de tipo numérico real. As instruções printf e scanf são utilizadas para escrever mensagens e ler variáveis, respectivamente. C ICLO DE DESENVOLVIMENTO 43 A compilação deste ficheiro com o comando gcc, em vez de produzir o ficheiro objecto, origina um conjunto de mensagens de erro: $ gcc -ansi dobro.c: In dobro.c:23: dobro.c:23: dobro.c:23: dobro.c:25: dobro.c:26: -pedantic -Wall -c dobro.c function ‘main’: ‘x0’ undeclared (first use in this function) (Each undeclared identifier is reported only once for each function it appears in.) parse error before ‘exit’ warning: control reaches end of non-void function Os erros reportados pelo compilador derivam dos chamados erros sintácticos, assim designados por corresponderem à não observação de uma ou mais regras sintácticas impostas pela linguagem. A interpretação das mensagens de erro requer alguma habituação, mas trata-se de um processo simples desde que seja feita uma leitura atenta do seu conteúdo. Um dos problemas correntes na interpretação das mensagens de erro resulta de, com alguma frequência, estes só serem detectados depois do local exacto do erro. As mensagens de erro geradas pelo gcc começam sempre por especificar o nome do ficheiro e, seguidamente, o número da linha em que o erro foi identificado. Neste caso, o primeiro erro é detectado na linha “y = 3.0 * cos(x0)”. A mensagem “‘x0’ undeclared” chama a atenção de que a variável x0 não existe, pelo que aquela linha deverá ser corrigida para “y = 3.0 * cos(x)”. Um segundo erro é identificado na linha 25 (exit(0);), sendo a mensagem “parse error before ‘exit”’. De facto, estritamente falando, o erro que existe é na linha anterior, já que falta o “;” obrigatório no final da instrução “printf(...)”. No entanto, dado que os espaços em branco e mudanças de linha são sintacticamente irrelevantes em C, o erro só é detectado no inı́cio da instrução seguinte. Finalmente, a última mensagem, na linha 26, é consequência do erro anterior: a ausência do “;” leva a que a instrução “exit(0)” não seja identificada e, como tal, o compilador avisa que chegou ao fim do ficheiro sem ter encontrado esta instrução. Note-se que a última mensagem surge reportada como aviso (warning) e não como erro. Enquanto que os erros propriamente ditos impedem o programa de ser compilado e executado, os avios limitam-se a chamar a atenção para potenciais falhas do programa, mas não impedem a sua compilação e execução. No entanto, salvo em casos excepcionais, os warning correspondem de facto a erros do programador, devendo ser corrigidos antes da execução do programa. Após a correcção dos erros sintáticos, a compilação do programa não origina qualquer mensagem, mas o mesmo não sucede com a “linkagem”: $ gcc -Wall -ansi -pedantic -c dobro.c $ gcc dobro.o -o dobro 44 D ESENVOLVIMENTO DE PROGRAMAS dobro.o: In function ‘main’: dobro.o(.text+0x2e): undefined reference to ‘cos’ collect2: ld returned 1 exit status Neste caso, existe um erro durante a “linkagem” do programa, indentificável pela mensagem “ld returned 1 exit status”, e que surge por o linker ld não ter encontrado um componente necessário ao programa. A mensagem “undefined reference to ‘cos”’ esclarece que o problema resulta da inexistência do código necessário para o cálculo da função coseno. Este código está disponı́vel, conjuntamente com outras funções matemáticas e trigonométricas, na biblioteca pré-compilada libm.a (em Unix, o nome das bibliotecas pré-compiladas tem o prefixo lib e a extensão .a). No entanto, o uso desta biblioteca deve ser explicitado no comando de linkagem. Assim, por exemplo, a inclusão de um biblioteca com o nome libxpto.a é feita especificando no comando de “linkagem” a opção -lxpto. No caso do programa dobro, a inclusão da biblioteca “libm.a” implica a adição da opção -lm no comando, de modo a obter-se uma “linkagem” sem erros. $ gcc -lm dobro.o -o dobro A execução do programa dobro conduz ao seguinte diálogo com o utilzador $ dobro Introduza o argumento: 0.1 O dobro do coseno de 0.100000 é 2.985013 $ dobro Introduza o argumento: 3.1416 O dobro do coseno de 3.141600 é -3.000000 $ Agora, o programa é executado aparentemente sem erros. No entanto, os mais atentos notarão que o dobro do coseno de 3.1416 deveria ser próximo de 2 e não 3. Uma rápida análise do código fonte revela que se definiu “y = 3.0 * cos(x)” em vez de “y = 2.0 * cos(x)”. Este tipo de erros, obviamente não detectáveis pelo compilador, designam-se por erros semânticos. Os erros semânticos são incomparavelmente mais difı́ceis de corrigir do que os erros sintácticos, já que derivam de erros na construção do programa e, como tal, não são automaticamente detectáveis. A detecção e correcção de erros semânticos é geralmente efectuada durante a fase de teste ou depuração (debug), em que o programador simula situações de funcionamento tı́picas do programa e analisa o seu comportamento. No entanto, em programas de complexidade elevada, a identificação de erros com base apenas na análise do resultado final do processamento é uma tarefa difı́cil. Em muitos casos, torna-se necessário analisar etapas intermédias do funcionamento C ICLO DE DESENVOLVIMENTO 45 interno do programa, observando os valores de variáveis e seguindo o fluxo de execução do programa. Os chamados “debuggers” são programas de teste que facilitam significativamente o processo de depuração e de identificação de erros durante o ciclo de desenvolvimento. 4.3.3 Depuração: gdb e ddd De modo poder ser testado com um debugger, o código fonte deve ser compilado com uma opção especial (-g), que permite que o ficheiro executável contenha “marcas” legı́veis pelo debugger que permitam fazer uma correspondência entre as instruções do ficheiro executável e do código fonte. A opção -g, embora seja conveniente durante a fase de teste, gera um programa executável mais lento e de maior dimensão e, como tal, não deve ser utilziada depois do processo de depuração ter sido concluı́do. No caso do programa “dobro”, a compilação e “linkagem” com opção de debug pode ser efectuada com o comando gcc -g -Wall -ansi -pedantic dobro.c -lm -o dobro O gdb é o debugger standard da gnu. Para executar o programa “dobro” com o auxı́lio do gdb deve ser usado o comando $ gdb dobro GNU gdb 19991004 Copyright 1998 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i386-redhat-linux"... (gdb) Neste ponto, o programa “dobro” não foi ainda executado, já que o debugger requer um comando especı́fico para esse efeito. Antes de iniciar a execução do programa, o código fonte pode ser consultado com o comando l (list) do gdb: (gdb) l 20 15 int main(){ 16 17 /* Declaração de variáveis */ 46 D ESENVOLVIMENTO DE PROGRAMAS 18 float x,y; 19 20 /* Bloco de instruções */ 21 printf(" Introduza o argumento: "); 22 scanf("%f",&x); 23 y = 3.0 * cos(x); 24 printf(" O dobro do coseno de %f é %f \n",x,y); Note-se que cada linha de programa é precedida do número da linha no ficheiro. O argumento 20 especifica que devem ser listada as 5 linhas antes e depois da linha 20 do ficheiro. Uma das principais vantagens do debuger é permitir a execução de um programa linha a linha ou, alternativamente, até a um determinado ponto especificado por um breakpoint. O comando (gdb) br 21 Breakpoint 1 at 0x80484b6: file dobro.c, line 21. indica que ao debugger que deve ser introduzido um breakpoint imediatamente antes da linha 21 de dobro.c. Se, depois deste comando, for dado o comando de execução do programa r (run), o programa só será executado até à linha 21, parando em seguida: (gdb) r Starting program: /ldisks/r015a/fcr/ist/manuais/intprog/dobro Breakpoint 1, main () at dobro.c:21 21 printf(" Introduza o argumento: "); Neste ponto, é possı́vel continuar a execução normal do programa, com o comando c (continue), ou executar o programa linha a linha, com o comando n (next). Neste último caso, ter-se-á, por exemplo (gdb) n 22 scanf("%f",&x); (gdb) n Introduza o argumento: 0.1 23 y = 3.0 * cos(x); (gdb) n 24 printf(" O dobro do coseno de %f é %f \n",x,y); (gdb) C ICLO DE DESENVOLVIMENTO 47 O conteúdo das variáveis x e y pode ser analisado com o comando p (print). Assim, (gdb) p x $8 = 0.100000001 (gdb) p y $9 = 2.98501253 (gdb) A continuação do programa até ao final pode ser obtida pelo comando c (continue): (gdb) c Continuing. O dobro do coseno de 0.100000 é 2.985013 Program exited normally. (gdb) Embora a utilização de um debugger não permita só por si identificar os erros semânticos de um programa, a possibilidade de análise das variáveis internas e de execução parcelar do programa faz desta ferramenta um importante auxiliar ao desenvolvimento e teste de programas. Se o terminal Unix utilizado tiver disponı́vel o sistema gráfico X, a utilização do gdb pode ser simplificada pela utilização da interface gráfica ddd. No caso do programa dobro, a execução do debugger tem lugar pelo comando $ ddd dobro dando origem à janela apresentada na figura 4.2. A janela inicial do ddd encontra-se dividida em duas partes. A parte inferior desta janela além de permitir interactuar directamente com o gdb, usando os comandos descritos anteriormente, deve ser utilizada para a introdução de dados no programa. Na janela superior, além da visualização do código fonte, é possı́vel definir breakpoints com o auxı́lio do botão do lado direito do rato. A execução do programa com os comandos c (continue), r (run), n (next) e s (step) é facilitada usando a janela auxiliar com os botões de comando. Durante a execução do programa, o valor das variáveis do programa pode ser consultado passando simplesmente o rato sobre o nome da variável na janela superior. Caso se pretenda uma visualização permanente de uma ou mais variáveis, deverá ser aberto um segmento de dados, seleccionando a opção do menu “View/Data Window”. Após este passo, é suficiente apontar a 48 D ESENVOLVIMENTO DE PROGRAMAS Figura 4.2: A interface gráfica ddd C ICLO DE DESENVOLVIMENTO 49 Figura 4.3: A interface gráfica ddd, com o segmento de dados visı́vel 50 D ESENVOLVIMENTO DE PROGRAMAS variável que se pretende visualizar no segmento do código fonte e, com o botão do lado direito do rato, seleccionar a opção Display. O valor da variável seleccionada surgirá no segmento superior (V. figura 4.3). Para mais informação relativamente à utilização do ddd para depuração de programas, deverá ser consultado o manual (Foundation, 2000). 4.4 Compilação em módulos separados Mesmo em programas de de complexidade reduzida, o código fonte pode atingir alguns milhares de linhas. Com o aumento da dimensão do programa, a manipulação do ficheiro com um editor torna-se progressivamente mais difı́cil, sobretudo quando é necessário localizar determinados blocos ou identificar segmentos em que são utilizadas determinadas variáveis. De modo a evitar a utilização de ficheiros de dimensão excessiva, a maioria das linguagens de alto nı́vel permite que o programa seja dividido por diversos ficheiros fonte, os quais são compilados individualmente. A junção dos vários ficheiros objecto é relizada durante o processo de “linkagem”. Não existem regras formais para realizar esta divisão, a qual depende em grande parte da metodologia do programador. No entanto, a divisão do programa não deve ser feita de forma arbitrária, devendo obedecer a critérios funcionais claros. Uma estratégia possı́vel para planear esta divisão baseia-se no agrupamento de conjuntos de funções e operações que dizem respeito a um mesmo tipo de dados. Com esta metodologia, é geralmente possı́vel chegar a conjunto de módulos que, embora com funções complementares no conjunto do programa, são funcionalmente independentes entre si. A correcta identificação dos blocos ou módulos funcionais do programa desde o inı́cio da análise do problema que se pretende resolver, permite, de um modo geral, simplificar significativamente o processo de teste e desenvolvimento. Com efeito, a identificação de módulos relativamente autónomos permite desenvolver e testar os diversos blocos constituintes do programa separadamente. Um erro frequente em programadores inexperientes é a estratégia de resolução horizontal do problema, tentando abordar todos os seus detalhes simultaneamente. Esta metodologia, além de originar programas com uma estrutura lógica e funcional muito mais intrincada, dificulta significativamente a identificação e correcção de erros. C OMPILAÇ ÃO EM M ÓDULOS SEPARADOS 51 Figura 4.4: Compilação e “linkagem” de um programa. 52 D ESENVOLVIMENTO DE PROGRAMAS 4.5 Bibliotecas estáticas e dinâmicas Já se referiu anteriomente que o processo de “linkagem” envolve a junção ao código objecto de blocos de instruções pre-compilados, disponı́veis no sistema sob a forma de bibliotecas. As bibliotecas podem ser estáticas ou dinâmicas. Embora o seu funcionamento, para o utilizador, seja semelhante na maioria das situações, é importante distinguir os dois tipos. Tanto as bibliotecas estáticas como as dinâmicas são consultadas durante o processo de “linkagem”, sendo identificados os blocos de instruçÕes necessários à execução do programa. No entanto, enquanto que nas bibliotecas estáticas os blocos assim identificados são incluı́dos de imediato no ficheiro executável, no caso das bibliotecas dinâmicas esta operação é adiada até à execução efectiva do programa. As bibliotecas dinâmicas4 permitem que o código executável tenha menor dimensão e, que o inı́cio da execução do programa seja, em geral, mais rápido. Este último facto é, aparentemente, contraditório com a necessidade de completar a “linkagem” no inı́cio da execução. No entanto, as bibliotecas dinâmicas, sendo idênticas para vários programas, encontram-se já frequentemente na memória central quando é dado o comando de execução do programa, o que permite que este tenha inı́cio mais rapidamente. A maior desvantagem das bibliotecas dinâmicas reside na redução de portabilidade do programa executável entre máquinas distintas. Com efeito, quando um programa executável utiliza bibliotecas dinâmicas e é copiado de uma máquina para outra é necessário garantir que as mesmas bibliotecas estejam disponı́veis na máquina de destino para que a execução seja possı́vel. O mesmo não sucede num programa que só utilize bibliotecas estáticas (“linkagem” estática), já que todo o código se encontra incluı́do no executável. Na figura 4.4 representa-se graficamente o processo de compilação, linkagem e execução de um programa constituı́do por diversos ficheiros fontes e envolvendo bibliotecas estáticas (libs1.a, libs2.a e libs3.a) e dinâmicas (libd1.so e libc.so). Neste exemplo, os comandos de compilação e “linkagem” poderiam ser, por exmplo, $ $ $ $ gcc gcc gcc gcc -Wall -ansi -pedantic -c main.c -Wall -ansi -pedantic -c modulo1.c -Wall -ansi -pedantic -c modulo2.c -ls1 -ls2 -ls3 -ld1 main.o modulo1.o modulo2.o No comando de “linkagem” não se especifica a biblioteca libc.so porque esta é uma biblioteca “standard” incluı́da automaticamente na chamdada ao “linker” pelo comando gcc. 4 Em Windows, as bibliotecas dinâmicas são conhecidas pelo nome e sufico dll, proveniente de dynamic loadable library O UTILIT ÁRIO make 53 Geralmente, todas as bibliotecas dinâmicas tem uma versão estática equivalente. No caso da figura 4.4 é provável que o sistema disponha também das bibliotecas estáticas libd1.a e libc.a. Por omissão, o linker utiliza preferencialmente as versões dinâmicas das bibliotecas. No entanto, caso se pretenda uma “linkagem” estática, esta é pode ser obtida especificando a opção -static na linkagem: $ gcc -static -ls1 -ls2 -ls3 -ld1 main.o modulo1.o modulo2.o 4.6 O utilitário make Em programas complexos, é frequente o programa fonte ser constituı́do por dezenas de ficheiros. Durante a fase de desenvolvimento, o programador edita estes ficheiros com frequência, sendo fácil perder o controlo de quais os que foram modificados e que devem ser recompilados, e os que não foram alteradas e que, como tal, não necessitam deste processo. Uma primeira solução para este problema é escrever um ficheiro com comandos (designado por script) de forma a que os comandos de compilação e “linkagem” fossem sempre executados em sequência para todos os ficheiros. Esta solução, embora razoável em programas de pequena dimensão, tem o inconveniente de poder ser muito demorada em caso de programas complexos. Assim, por exemplo, no caso de um programa com 50 ficheiros fonte, não é eficente recompilar 50 ficheiros apenas porque se modificou 2 ou 3. No entanto, chamar o compilador manualmente para os dois ou três ficheiros modificados, além de ser pouco prático, conduz facilmente a situacões em que um ou mais ficheiros não são actualizados, originando programas executáveis inconsistentes com o porgrama fonte. O utilitário make permite ultrapassar esta dificuldade através de um sistema de regras, especificadas pelo utilziador, combinadas com a comparação das horas de modificação dos vários ficheiros. Assim, por exemplo, o utilizador pode especificar uma regra que o ficheiro xpto.o deriva do ficheiro xpto.c por um comando de compilação. Sempre que o comando make é executado, são comparadas as datas dos ficheiros xpto.o e xpto.c e o compilador será chamado sempre que a data de alteração deste último for mais recente que a do primeiro. As regras do utilitário make são escritas num ficheiro especial com o nome makefile. A makefile pode incluir um número ilimitado de regras e pode atingir uma complexidade elevada em projectos de programação de dimensão elevada. Embora o utilitário make possa ter regras extremamente elaboradas, na sua versão básica cada regra tem uma estrutura simples. Cada regra é constituı́da por duas linhas. A primeira linha indica a estrutura de depências de um dado ficheiro e a segunda linha especifica o comando que permite gerar o ficheiro a partir das suas dependências. A segunda linha da regra distingue-se da primeira por conter obrigatoriamente um caracter de 54 D ESENVOLVIMENTO DE PROGRAMAS tabulação na primeira posição. Note-se que este caracter é uma fonte frequente de mal entendidos na makefile, já que não é possı́vel distinguir visualmente um caracter de tabulação de uma sequência de oito espaços em brancos, mas só o primeiro é correcto na segunda linha da regra. No caso do ficheiro xpto.o referido anteriomente, a correspondente regra da Makefile teria a estrutura xpto.o: xpto.c gcc -Wall -ansi -pedantic -c xpto.c Basicamente, esta regra especifica que o ficheiro xpto.o depende de xpto.c, enquanto que a segunda linha especifica o comando que permite gerar o ficheiro xpto.o a partir de xpto.c. No caso de um programa utilizado como exemplo na secção 4.4, a estrutura completa da makefile poderia ser a seguinte: # #FILE # makefile # #CONTENTS # Makefile para geração do programa de exemplo # da secção 4.4 # #CREATOR/CONTACT # Fernando Mira da Silva, IST ([email protected]) # # a.out: main.o modulo1.o modulo2.o gcc -ls1 -ls2 -ld1 main.o modulo1.o modulo2.o main.o: main.c gcc -c -Wall -ansi -pedantic main.o modulo1.o: modulo1.c gcc -c -Wall -ansi -pedantic modulo1.o modulo2.o: modulo2.c gcc -c -Wall -ansi -pedantic modulo2.o O UTILIT ÁRIO make 55 Após a preparação da makefile, a actualização do ficheiro executável apenas requer a execução do comando make. Este começa por ler a makefile e, seguidamente, executará a sequência de operações necessárias para gerar ou actualizar o ficheiro especificado na primeira regra da makefile (neste caso, a.out). Com excepção da primeira regra, que deve especificar o ficheiro a actualizar pelo comando make, as regras seguintes têm uma ordem arbitrária. De forma a simplificar a construção da makefile, algumas regras são automáticas e não precisam de ser explicitadas na makefile. De facto, o utilitário make dispõe de uma regra implı́cita que indica que um ficheiro com a extensão .o pode ser gerado a partir de um ficheiro com extensão .c através do gcc. Assim, a makefile do exemplo anterior poderia ser simplificada como se segue: # #FILE # makefile # #CONTENTS # Makefile para geração do programa de exemplo # da secção 4.4 (versão simplificada) # #CREATOR/CONTACT # Fernando Mira da Silva, IST ([email protected]) # # CFLAGS=-Wall -ansi -pedantic a.out: main.o modulo1.o modulo2.o gcc -ls1 -ls2 -ld1 main.o modulo1.o modulo2.o Neste exemplo, embora se tenham omitido as regras implı́citas de compilação, foi necessário especificar através de uma variável (CFLAGS) quais as opção de compilação que devem ser adoptadas pela regra implı́cita (por omissão, o compilador é chamado apenas com a flag “-c”, modo que é desaconselhável em programas novos). Capı́tulo 5 Editores de texto 5.1 Introdução Sendo relativamente simples o desenvolvimento de um editor de texto, e sendo este uma ferramenta de uso frequente em Unix, os editores de texto multiplicaram-se de modo a satisfazer os gostos de vários tipos de utilizadores. emacs, vi, pico e joe são alguns destes editores. Dado que o código fonte não é mais que um ficheiro de texto, qualquer destes editores pode ser utilizado para o desenvolvimento de programas em C. A escolha do editor de texto é uma opção pessoal de cada utilizador. Normalmente, editores mais sofisticados tendem a requerer uma fase de habituação mais prolongada, mas o investimento inicial é normalmente recompensado pela maior flexibilidade e facilidades disponı́veis. Para a programação em código fonte, os modos formatação automática do emacs fazem deste um dos editores preferidos de muitos programadores. 5.2 5.2.1 O editor emacs Introdução O editor emacs foi escrito por Richard Stallman no inı́cio do projecto GNU e tem sido objecto de um desenvolvimento contı́nuo desde então. Actualmente, é considerado o mais completo e configurável dos editores de texto disponı́veis em Unix. Duas caracterı́sticas fazem do editor emacs particularmente atractivo em ambientes de programação. Por um lado, o emacs dispõe de um sistema de formatação automática para várias linguagens de programação (entre as quais, o C). A formatação automática é particularmente útil 58 E DITORES DE TEXTO para identificar alguns erros simples que são correntes em C: parenteses e chavetas não equilibrados, ciclos mal delimitados, etc. Por outro lado, o editor emacs permite chamar directamente um comando compilação e, caso existam erros, posicionar o cursor no ficheiro fonte próximo do local onde foi detectado o erro. 5.2.2 Modos de edição e de comando O emacs é chamado simplesmente com o comando emacs. Se o terminal do utilizador dispuser do sistema X, o emacs é aberto numa janela gráfica, sendo possı́vel utilizar o rato para posicionar o cursor, seleccionar texto, e aceder aos menus que se encontram no topo superior da janela. Após o seu inı́cio, o emacs apresenta uma janela ao utilizador constituı́da por duas partes. A superior, que ocupa a quase totalidade do espaço visı́vel, corresponde ao buffer de edição propriamente dito. A parte inferior da janela é constituı́da porm uma única linha, onde são introduzidos os comandos do editor, designado por minibuffer. Durante a edição, o texto é introduzido da forma habitual no buffer de edição. O acesso ao modo de comando tem geralmente lugar através de caracteres especiais, através de combinações especiais de teclas. No seguimento, utiliza-se a notação C- para indicar que a tecla <control> (ou <ctrl> deve ser premida simultaneamente com o caracter seguinte. Assim, por exemplo, C-c indica que devem ser premidas simultaneamente as teclas <ctrl> e c. Adicionalmente, o emacs prevê a existência de uma tecla especial adicional, designada por meta, que permite o acesso a um segundo conjunto de funções especiais. Assim, vários comandos do emacs são descritos pela notação M- para indicar que a tecla meta deve ser premida simultaneamente com o caracter seguinte. Assim, por exemplo, M-x indica que devem ser premidas simultaneamente as teclas meta e c. Em terminais gráficos ou terminais de PC, a tecla meta corresponde às teclas Alt. Em terminais que não tenham disponı́vel a tecla Meta, esta pode ser substituı́da premindo em sequência a tecla escape (Esc) e a tecla especificada seguinte. O acesso ao minibuffer pode ser conseguido através da tecla M-x. Na maioria dos comandos, o emacs regressa automaticamente ao buffer de edição após este ser finalizado. No entanto, caso seja necessário, o cancelamento do modo de comando é possı́vel com o comando C-G. 5.2.3 Leitura de ficheiros A leitura de um ficheiro tem lugar com o comando C-X C-F, o qual solicita a indicação do nome do ficheiro a editar no minibuffer. O comando C-X C-S grava o ficheiro em edição. O emacs permite a edição simultânea de diversos ficheiros, colocando cada um num buffer de O EDITOR VI 59 edição separado. O comando C-X C-B lista todos os buffers correntes, enquanto que o comando C-X B permite mudar o buffer em edição. 5.2.4 Formatação automática Ao editar um ficheiro com extensão .c, o emacs entra automaticamente no modo C, realizando uma formatação (indentação) automática do código fonte. Para posicionar o cursor no local correcto ou indentar uma dada linha no modo C basta em qualquer altura de introdução de uma linha premir a tecla <Tab>. 5.2.5 Compilação e localização de erros O comando de compilação é chamado com o comando M-C-G, seguido da tecla de <Enter>. Por omissão, o comando de compilação é make -k, mas pode ser editado em qualquer altura de forma a adpatá-lo a outra situação. Quando o comando de compilação é executado dentro do emacs, as mensagens resultantes do comando surgem dentro de um “buffer” designado compilation. Caso tenha havido erros, o comando “M-x compile-goto-error” posiciona o cursor no código fonte, próximo do erro detectado. 5.3 O editor vi 5.3.1 Introdução O editor de texto vi é uma aplicação standard do sistema Unix. Embora existam actualmente editores mais sofisticados, o editor vi é ainda extremamente popular devido sobretudo à sua eficiência e facilidade de manuseamento. No entanto, este editor apresenta algumas caracterı́sticas distintas das encontradas em editores de texto de outros sistemas, sendo por vezes necessário alguma habituação ao seu modo particular de funcionamento. O editor vi pode ser invocado pela linha de comando $ vi <nome do ficheiro a editar ou criar> Na altura em que é invocado, o vi copia o ficheiro a editar para uma zona de memória designada por buffer de trabalho. Todas as alterações ao ficheiro são efectuadas primeiro nesta zona de trabalho e só posteriormente copiadas em definitivo para o disco. Este processo ocorre no final da 60 E DITORES DE TEXTO sessão de edição ou quando explicitamente indicado pelo utilizador, evitando-se assim que erros graves na edição se traduzam numa alteração irrecuperável do ficheiro em disco. O editor vi tem dois modos de funcionamento distintos: modo de comando e modo de edição. No modo de comando, o vi aceita sequências de teclas como comandos, executando cada comando à medida que estes são introduzidos no teclado. No modo de edição, as teclas premidas correspondem a texto que se pretende inserir no ficheiro, surgindo no monitor os caracteres à medida que são introduzidos. A descrição que se segue, embora não exaustiva, descreve a maioria dos comandos necessários a uma sessão de edição com o vi . 5.3.2 Modo de edição No inicio de uma sessão de edição, o vi encontra-se no modo de comando. A passagem ao modo de edição efectua-se pela indicação de um comando especı́fico para este efeito. A passagem do modo de edição ao modo de comando faz-se premindo a tecla escape em qualquer altura do processo de edição. Quando o editor se encontra no modo de comando, a inserção de texto pode efectuar-se, por exemplo, deslocando o cursor para a zona onde se pretende inserir texto, e premindo a tecla i. A partir deste momento, o editor entra no modo de inserção, surgindo o texto no monitor à medida que for sendo introduzido. Note-se que existem outros comandos que permitem passar do modo de comando ao modo edição (V. secções 5.3.4 e 5.3.6). Tal como é habitual, a tecla <del> ou <backspace> pode ser usada para corrigir o último caracter introduzido. No entanto, os caracteres apagados permanecem normalmente no monitor até serem corrigidos ou se carregar na tecla de <return>. Este modo de funcionamento, embora pouco usual, minimiza os acessos ao monitor, reduzindo o overhead do processo. 5.3.3 Movimentação do cursor A movimentação do cursor pode ser realizada no modo de comando pela utilização das teclas descritas no seguimento. Note que a movimentação do cursor de uma posição em qualquer das direções efectua-se pelas teclas h, j, k e l as quais se encontram em sequência no teclado. • h Move o cursor um caracter para a esquerda. • l Move o cursor um caracter para a direita. • j Move o cursor um caracter para baixo. O EDITOR VI 61 • k Move o cursor um caracter para cima. • k Move o cursor um caracter para cima. • H Move o cursor para o inicio do monitor. • M Move o cursor para a linha central do monitor. • L Move o cursor para a última linha. • C-D Avança meio écran de texto. • C-U Recua meio écran de texto. • C-F Avança um écran de texto. • C-B Recua um écran de texto. 5.3.4 Inserir texto Quando se encontra no modo de comando, o vi pode ser colocado no modo de edição utilizando os seguintes comandos: • i Insere texto antes da posição actual do cursor. • a Insere texto após a posição actual do cursor. • o Insere uma linha a seguir à linha corrente. • O Insere uma linha antes da linha corrente. • r Substitui o caracter existente na posição do cursor. • R Substitui caracteres a partir da posição actual do cursor. 5.3.5 Apagar texto Quando se encontra no modo de comando, o vi pode apagar texto já introduzido com os seguintes comandos: • x Apaga o caracter corrente. • dd Apaga a linha corrente. • 5dd Apaga 5 linhas, com inı́cio na linha corrente. 62 E DITORES DE TEXTO • d0 Apaga desde o inı́cio da linha até à posição do cursor. • dw Apaga desde a posição actual até ao fim da palavra. • db Apaga desde a posição actual até ao inı́cio da palavra. • d<ret> Apaga 2 linhas de texto. O comando u pode ser usado para desfazer (undo) a última operação de apagar texto. 5.3.6 Mudar texto Os seguintes comandos podem ser usados para substitui texto: • cw Mudar o texto desde a posição actual do cursor até ao fim da palavra. • c4w Mudar o texto desde a posição actual do cursor até ao fim da terceira palavra seguinte. • cb Mudar o texto desde a posição actual do cursor até ao inı́cio da palavra. • cc Mudar toda a linha corrente. Ao utilizar os comandos de mudar texto, a linha só é actualizada totalmente após a passagem novamente ao modo de comando. Assim, os caracteres que surgem no écran podem não corresponder directamente ao estado actual do ficheiro. Por exemplo, se uma palavra pequena for substituida por outra com maior número de caracteres, os últimos caracteres introduzidos podem surgir por cima de texto que não se pretende alterar. Ao passar ao modo de comando verifica-se no entanto que o efeito obtido é o desejado. 5.3.7 Procurar texto Para procurar um dada sequência de texto no ficheiro, passar ao modo de comando e usar o comando / seguido da sequência de texto que se pretende procurar e da tecla <return>. Além deste, os seguintes comandos podem ser usados para procurar texto: • n Repete a última operação de procura (i. e., usando a mesma sequência de caracteres). • N Repete a última operação de procura, mas recuando no ficheiro. O EDITOR VI 63 5.3.8 Substituir texto Para substituir uma sequência de caracteres por outra podem ser usados os comandos de substituição de texto. Nos exemplos seguintes, admite-se que se pretende substituir a sequência de caracteres xpto por abdefg. Admite-se que se está inicialmente no modo de comando. • :s/xpto/abdefg/g Substitui a sequência de caracteres em todo o ficheiro. • :<endereços>s/xpto/abdefg/g Substitui a sequência de caracteres nas linhas especificadas do endereço. O endereço pode ser o número de uma linha, aplicando-se neste caso o comando apenas a essa linha, ou dois números de linha separados por um ,. Neste último caso, a substituição processa-se na gama de linhas especificadas. Como número de linha podem ser usados, além do valor numérico, os sı́mbolos . (linha corrente) e $ (última linha do ficheiro). São exemplos da utilização de endereços no comando de substituição: – :2,.s/xpto/abdefg/g Substitui a sequência de caracteres desde a linha 2 até à linha actual. – :.,100s/xpto/abdefg/g Substitui a sequência de caracteres desde a linha actual até à linha 100. – :20,$s/xpto/abdefg/g Substitui a sequência de caracteres desde a linha actual até ao fim do ficheiro. – :.,.+4/xpto/abdefg/g Substitui a sequência de caracteres desde a linha actual até à quarta linha seguinte. – :7s/xpto/abdefg/g Substitui a sequência de caracteres na linha corrente. 5.3.9 Cortar, copiar e mover texto Sempre que um comando de apagar é usado, o material retirado é colocado numa zona especial de memória designada por buffer temporário. É a existência deste buffer que possibilita a utilização do comando u (undo), descrito anteriormente. É possı́vel colocar o texto apagado numa zona alternativa do ficheiro usando o comando put: • p Insere o texto existente no buffer temporário na posição a seguir ao cursor. • P Insere o texto existente no buffer temporário na posição anterior ao cursor. O editor vi permite utilizar 26 buffers alternativos que também podem ser usadas para guardar texto temporariamente numa sessão de edição. Ao apagar texto, ou ao usar o comando de put, é 64 E DITORES DE TEXTO possı́vel usar um buffer alternativo fazendo preceder o comando de aspas (”) e de uma letra do alfabeto. Existem 26 buffers deste tipo, cada um correspondendo a uma letra do alfabeto. Assim, por exemplo: • ”h4dd Apaga 4 linhas de texto e colocá-lo no buffer h. • ”hp Coloca o texto existente no buffer h na posição a seguir ao cursor. Note-se que, geralmente, é usada uma letra minúscula para designação do buffer. Neste caso, o conteúdo anterior do buffer, caso exista, é apagado. Se se usar uma letra maiúscula, o texto apagado é adicionado (sequencialmente) ao texto já ali colocado por comandos anteriores. Por vezes, é conveniente copiar texto para o buffer temporário ou um buffer alternativo sem o apagar da posição onde se encontra no buffer de trabalho. Esta operação pode ser obtida com o comando y, o qual tem exactamente as mesmas variantes do comando d. Assim, para copiar texto para o buffer temporário podem ser usados os seguintes comandos: • yy Copia a linha corrente. • 5yy Copia 5 linhas, com inı́cio na linha corrente. • y0 Copia desde o inı́cio da linha até à posição do cursor. • yw Copia desde a posição actual até ao fim da palavra. • yb Copia desde a posição actual até ao inı́cio da palavra. • y<ret> Copia 2 linhas de texto. Tal como anteriomente, é possı́vel usar um buffer alternativo fazendo preceder o comando de aspas (”) e de uma letra do alfabeto. 5.3.10 Outros comandos Os seguintes comandos são também frequentemente usados no vi : • J Junta a linha actual e a próxima. • C-g Imprime informação sobre o ficheiro a ser editado. • :w Actualiza o ficheiro • :w nome Escreve o conteúdo do buffer de trabalho para o ficheiro nome. O S EDITORES PICO E JOE 65 • :r nome Lê o conteúdo do ficheiro nome para o buffer de trabalho. O texto lido é inserido, sem sobreposição, ao já existente. O texto é inserido a seguir à linha corrente. 5.3.11 Saı́r Para abandonar o vi , os seguintes comandos podem ser usados: • ZZ Actualiza o ficheiro e sai do vi . • :q Abandona o processo de edição. • :q! Abandona o processo de edição sem pré-aviso de possı́veis alterações não actualizadas no ficheiro. 5.4 Os editores pico e joe Os editores pico e joe são muito menos sofisticados que os editores emacs e vi mas, por este motivo, a sua utilização é extremamente simples e intuitiva. No caso do editor pico, os códigos de acesso aos principais comandos surgem sempre nas últimas duas linhas do buffer de edição, pelo que não é necessário a sua memorização. No editor joe, a linha de topo recorda que a sequência C-K H dá acesso ao modo de ajuda (help), onde são listadas as sequências de acesso aos principais comandos. Embora os editores pico e joe sejam atractivos numa primeira utilização, é necessário ter em atenção que não têm disponı́veis facilidades importantes como a edição simultânea de vários ficheiros e, sobretudo a formatação/indentação automática de ficheiros disponı́vel no emacs. Capı́tulo 6 Textos e manuais complementares Pretende-se com este texto facilitar uma primeira abordagem ao sistema operativo Unix e a algumas das ferramentas necessárias ao desenvolvimento de programas neste sistema. Embora se pretenda que este manual seja tanto quanto possı́vel completo a um nı́vel introdutório, é evidente que a a diversidade e sofisticação das ferramentas envolvidas não permita a sua condensação num documento desta dimensão. Neste capı́tulo apresenta-se um extenso conjunto comentado de materiais bibliográficos cuja referência detalhada se encontra na secção de “Bibliografia” deste manual. Na sua grande maioria, os tópicos abordados extravasam largamente as necessidades do estudante médio que pretenda apenas uma primeira abordagem à Programação e ao sistema operativo Unix, pelo que a sua consulta não é de forma alguma obrigatória. No entanto, tratam-se de textos que podem ser úteis aos leitores mais interessados, para consulta ou para o aprofundamento de conhecimentos relativamente a tópicos especı́ficos. Na lista de referências que se seguem, deu-se preferência a textos disponı́veis livermente na internet, a maioria dos quais resultantes do chamado LDP (Linux Documentation Project), o qual tem por objectivo organizar e sistematizar manuais e guias referentes ao sistema operativo Linux e software da GNU. É possı́vel aceder a um mirror do LDP no IST em http://ldp.ist.utl.pt/. De destacar que, além de alguns manuais e guias com a organização habitual de um livro, o LDP inclui um conjunto extenso de pequenos textos introdutórios a tópicos especı́ficos designados por HOWTO e que, como o nome indica, são manuais muito simple e curtos que apresentam soluções (frequentemente em formato de receita, sem grandes aprofundamentos técnicos) para muitos dos problemas que frequentemente surgem com o sistema operativo Linux (embora a utilidade de muitos extravase o âmbito restrito do sistema Linux). Além de disponı́veis nas páginas do LDP, muitos destes textos estão por vezes disponı́veis nas máquinas linux sob os directórios /usr/doc/HOWTO e /usr/doc/HOWTO/mini. 68 T EXTOS E MANUAIS COMPLEMENTARES 6.1 Sistema Operativo Unix e Linux Para os interessados em instalar Linux num PC, existem hoje em dia diversas empresas que distribuem pacotes completos de Linux com um conjunto alargado de aplicações open source incluı́das e cuja instalação é quase automatizada. Entre as mais conhecidas encontram-se a Red Hat (a mais frequente no IST), Slackware, Debbian, SUSE e a Caldera. Saliente-se que estas empresas não vendem o software em si, já que este é de distribuição e cópia livre. O preço destes pacotes, de um modo geral relativemente baixo, destina-se apenas a cobrir os custos de distribuição, preparação do conjunto e software de instalação e de suporte ao cliente. Note-se que é possı́vel e simples instalar no mesmo PC dois sistemas operativos, desde que estes residam em partições distintas. Um bom HOWTO introdutório, fácil e rápido de seguir, é (Raymond, 2000). Um texto mais completo do LDP para apoio à instalação do Linux é (Welsh e outros , 1998). Complementarmente, (Greenfield, 1996) constitui um bom manual do Linux para o utilizador. Um livro que constitui também uma boa condensação do fundamental do Unix na óptica do utilizador é (Robbins, 1999). Para os interessados na implementação de sistemas operativos, (Marques e Guedes, 1990) é um bom texto introdutório, focando vários aspectos do sistema Unix. (Bach, 1986) é geralmente considerado uma das melhores referências pedagógicas para aprendizagem do sistema Unix, tendo sido o texto seguida por Linus Torvalds nas fases iniciais da implementação do Linux. Este texto inclui uma descrição aprofundada de diversos detalhes de implementação do núcleo e do sistema de ficheiros do Unix, tal como concebido originalmente por Ritchie e Thompson(Ritchie e Thmompson, 1974). Um texto menos académico e mais focado na implementação actual do núcleo do sistema operativo Linux pode ser encontrado em (Rusling, 1998). 6.2 Ambiente de trabalho Tal como referido anteriomente, o interpretador de comandos (shell) actualmente mais utilizado no sistema operativo Linux é o bash. Uma primeira introdução a esta shell pode ser encontrado em (Orr, 1996), que constitui um pequeno HOWTO suficiente para uma primeira abordagem. Um texto mais aprofundado e completo é o livro (Newham e Rosenblatt, 1998). Relativamente ao sistema gráfico X11, que serve frequentemente de interface ao sistema operativo Unix, uma primeira abordagem pode ter por base a referência (Brigleb, 1999), uma vez mais um HOWTO do LDP. Um texto mais técnico e aprofundado sobre o sistema de X11 pode ser encontrado em (Quercia e O’Reilly, 1993). Embora este livro esteja parcialmente ultrapassado, P ROGRAMAÇ ÃO E DEPURAÇ ÃO DE PROGRAMAS EM C 69 inclui uma boa descrição dos princı́pios e protocolos ainda hoje adoptados pelo sistema X11. 6.3 Programação e depuração de programas em C O primeiro livro de divulgação da linguagem C foi publicado por Kernighan e Ritchie em 1978 (Kernighan e Ritchie, 1978). Este texto, pela sua clareza e qualidade, é ainda hoje considerado uma referência incontornável da linguagem C. Embora sem grandes alterações de forma, este texto foi revisto anos mais tarde de forma a adaptar-se ao standard ANSI (Kernighan e Ritchie, 1990). Este livro não é, no entanto, o mais adequado para uma primeira aprendizagem de Programação. Para este efeito, aconselha-se a referência (Damas, 1999), onde a apresentação da linguagem C é acompanhada de uma introdução às técnicas de programação procedimental. Uma referência interessante a nı́vel introdutório do C é também (Oualline, 1997) e, do mesmo autor, mas para os interessados em explorar o C++, (Oualline, 1995). A escrita de programas em unix requer a utilização de um editor de texto. Para além do editor vi, brevemente descrito nestas folhas, existem diversos editores alternativos cuja escolha depende, em grande parte, do gosto do utilizador. De um modo geral, o editor emacs é considerado o mais completo disponı́vel no sistema operativo Unix. Embora as suas sequências de comandos requeiram alguma habituação, a sua utilização é fortemente recomendada. Uma boa introdução ao emacs pode ser encontrada no HOWTO (Zawodny, 1999). Uma referência mais completa sobre este editor é (Cameron e outros, 1996). Informações especı́ficas relativamente ao compilador de C (gcc) utilizado no sistema operativo Linux podem ser encontradas em (Barlow, 1996). Para a depuração de programas em Linux utilizando o ddd, é possı́vel recorrer ao manual desta ferramenta (Foundation, 2000), também disponı́vel na rede. Relativamente ao utilitário make, o seu manual (Stallman e McGrath, 2000) encontra-se igualmente disponı́vel na rede. De um modo geral, uma boa referência para uma abordagem integrada da programação em UNIX/Linux é (Loukides e Oram, 1996). Este manual inclui uma introdução à utilização do editor emacs, compilador gcc, utilitário make, debugger gdb, além de introduzir a ferramenta RCS para manutenção de software. Bibliografia Bach, M. J. (1986). The design of the Unix Operating System. Prentice-Hall. Barlow, D. (1996). The Linux GCC HOWTO. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/HOWTO/GCC-HOWTO/index.html. Brigleb, R. (1999). The X Window User HOWTO. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/HOWTO/XWindow-User-HOWTO.html. Cameron, D., Rosenblatt, B., e Raymond, E. (1996). Learning GNU Emacs. Unix series. O’Reilly, 2nd edition. csn (2000). NT holds up against linux onslaught; others suffer. Client Server News, (337). Damas, L. (1999). Linguagem C. FCA - Editora de Informática. Foundation, F. S. (2000). DDD - Data Display Debugger. http://www.gnu.org/manual/ddd/. Free Sofwtare Foundation, Greenfield, L. (1996). The Linux User’s Guide. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/guides.html. Kernighan, B. e Ritchie, D. (1978). The C Programming Language. Prentice-Hall. Kernighan, B. e Ritchie, D. (1990). The C Programming Language - The ANSI edition. PrenticeHall. Loukides, M. e Oram, A. (1996). Programming with GNU software. Unix series. O’Reilly & Associates, Inc. Marques, J. A. e Guedes, P. (1990). Fundamentos de Sistemas Operativos. FCA - Editora de Informática. Newham, C. e Rosenblatt, B. (1998). Learning the bash Shell. Unix series. O’Reilly, 2nd edition. Orr, G. (1996). Bash Prompt HOWTO. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/HOWTO/Bash-Prompt-HOWTO.html. 72 B IBLIOGRAFIA Oualline, S. (1995). Practical C++ Programming. Unix series. O’Reilly & Associates, Inc, 3thd edition. Oualline, S. (1997). Practical C Programming. Unix series. O’Reilly & Associates, Inc, 3thd edition. Quercia, V. e O’Reilly, T. (1993). Volume 3: X Window System User’s Guide. X Window System series. O’Reilly & Associates, Inc. Raymond, E. S. (2000). The Linux Installation HOWTO. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/HOWTO/Installation-HOWTO.html. Ritchie, D. e Thmompson, K. (1974). The unix timesharing system. Commun ACM, páginas 365–375. Robbins, A. (1999). Unix in a Nutshell: System V Edition. Unix series. O’Reilly & Associates, Inc. Rusling, D. A. (1998). The Linux Kernel. http://ldp.ist.utl.pt/guides.html. LDP - The Linux Documentation Project, Stallman, R. M. e McGrath, R. (2000). GNU Make. http://www.gnu.org/manual/html node/make toc.html. Free Sofwtare Foundation, Tanenbaum, A., Linus Torvalds, K. T., e outros (1993). Debate over Linux/Minix - Exchanged e-mails. http://www.oreilly.com/catalog/opensources/book/appa.html. Welsh, M. e outros (1998). Installation and Getting Started Guide. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/guides.html. Williams, J. (1993). Hard Drive: Bill gates and the Making of the Microsoft Empire. HarperCollins Publishers, New York, NY. Zawodny, J. D. (1999). Emacs Beginner’s HOWTO. LDP - The Linux Documentation Project, http://ldp.ist.utl.pt/HOWTO/Emacs-Beginner-HOWTO.html.