Ambientes de programação. Estudo breve de vários casos.
Um ambiente minimal é tipicamente constituído por:
Um ambiente sofisticado é tipicamente constituído por:
javac Compilador java Executor de programas independentes javadoc Gerador de documentação appletviewer Executor de applets jdb Depurador javap Disassembler javah Gerador de header files para métodos nativos escritos em C
Repare que a lista de ferramentas abaixo inclui um profiler que serve para o programador descobrir quais as partes do programa onde se gasta mais tempo. Essas são as partes do programa que mais interessa otimizar.
ocaml Interpretador ocamlc Compilador para a máquina virtual CAML ocamlopt Compilador de código nativo ocamlrun Executor da máquina abstrata CAML ocamlbrowser Permite navegar e inspecionar o conteúdo dos módulos de biblioteca ocamldebug Depurador de código fonte ocamldoc Gerador de documentação ocamldep Inspeciona um conjunto de ficheiros fonte e gera automaticamente informação de dependências para a ferramenta make ocamlcp Profiler, insere no código fonte a contagem de quantas vezes cada função é chamada, etc. ocamlprof Interpreta o output da execução de programas processados usando ocamlcp ocamllex Gera reconhecedores de expressões regulares diretamente a partir dessas expressões ocamlyacc Gera parsers diretamente a partir de gramáticas LALR(1) ocamlp4 Processador do código fonte de programas ocaml (para pretty-print, por exemplo) ocamldumpobj Disassembler de ficheiros .cmo ocamlobjinfo Inspeciona ficheiros .cmo, .cmi, .cma
O Unix disponibiliza uma grande quantidade de ferramentas de desenvolvimento, mas deve ser dito que essas ferramentas foram nascendo de forma caótica e que não há uma interface consistente entre elas. Algumas ferramentas são também muito complexas, embora cumpram os seus objetivos de forma admirável, na maior parte dos casos.
autoconf Ferramenta para criar projetos de software portáveis e reconfiguráveis automake Gerador automático de makefiles libtool Ferramenta para criar bibliotecas de software
Costuma ser usado para automatizar transformações de ficheiros no contexto de projetos pequenos ou médios. A sua principal utilização é determinar automaticamente as partes do projeto precisam de ser recompiladas e executar os comandos necessários para concretizar a recompilação. O make considera as dependências entre ficheiros e as datas das últimas modificações para saber o que é preciso fazer em cada momento.
Cada projeto contém um ficheiro geralmente chamado Makefile onde se declaram as dependências entre os ficheiros, e onde se definem regras que dizem como os diversos ficheiros devem ser gerados. Para além de regras de recompilação, podem ser definidas outras ações, tais como apagar os ficheiros auxiliares do projeto, ou produzir o arquivo da distribuição do projeto.
Eis a estrutura de cada regra:
Assume-se geralmente que o target designa um ficheiro que deve ser gerado. Mas, por vezes queremos incluir comandos implementados através de "falsos" targers, e para isso usa-se a declaração ".PHONY".
O seguinte exemplo é o ficheiro Makefile que foi usado num projeto antigo de LAP:
APP = dt VERSION = 0.1 COMP = ocamlc INTERFS = DTree.mli OBJS = DTree.cmo dt.cmo GROUP = 123_456 $(APP): $(OBJS) $(COMP) -o $(APP) $(INTERFS) $(OBJS) %.cmo: %.ml $(COMP) $(INTERFS) -c $< .PHONY: clean clean: rm -f $(APP) *.cmo *.cmi .PHONY: dist dist: clean mkdir $(GROUP) cp *.ml *.mli $(GROUP) zip -r $(GROUP).zip $(GROUP) rm -rf $(GROUP) |
$ ls dt.ml DTree.ml DTree.mli Makefile $ make DTree.cmo ocamlc DTree.mli -c DTree.ml $ make ocamlc DTree.mli -c dt.ml ocamlc -o dt DTree.mli DTree.cmo dt.cmo $ make clean rm -f dt *.cmo *.cmi $ make dist rm -f dt *.cmo *.cmi mkdir 123_456 cp *.ml *.mli 123_456 zip -r 123_456.zip 123_456 adding: 123_456/ (stored 0%) adding: 123_456/DTree.ml (deflated 72%) adding: 123_456/dt.ml (deflated 67%) adding: 123_456/DTree.mli (deflated 65%) rm -rf 123_456 $ ls 123_456.zip dt.ml DTree.ml DTree.mli Makefile |
O seguinte programa está errado:
char str[128] ; void f(void) { char *pt = str ; int i ; for( i = 0 ; i < 10000 ; i++ ) // <-- Provoca estoiro *pt++ = 'a' ; } void g(void) { f() ; } int main() { g() ; return 0 ; } |
$ ./a Segmentation fault (core dumped) $ gdb ./a GNU gdb 6.6-debian Copyright (C) 2006 Free Software Foundation, Inc. (gdb) run Starting program: /media/EXTERN/amd1/z/a Program received signal SIGSEGV, Segmentation fault. 0x0804835d in f () <-- Estoiro na função f (gdb) backtrace #0 0x0804835d in f () #1 0x0804837b in g () #2 0x08048390 in main () <-- Pilha de execução no momento do estoiro (gdb) |
O CVS, divulgado em 1986, foi o primeiro sistema de controlo de versões a suportar um repositório partilhado por vários utilizadores.
Uma ferramenta como o CVS é essencial para a viabilidade do software livre, pois este tipo de software é tipicamente desenvolvido coletivamente por um grande número de voluntários geograficamente espalhados e não pagos. Nenhum desses voluntários teria tempo nem paciência para processar manualmente as numerosas submissões de código novo ou corrigido.
Uma ferramenta do tipo do CVS também faz falta no desenvolvimento de software proprietário, mas no caso do software livre a questão é mais evidente.
Subversion (2004) - O Subversion foi criado para resolver as insuficiências mais evidentes do CVS. Foi a primeira alternativa popular ao CVS e continua a ser muito usado.
Git (2005) - Mas, atualmente, o sistema mais usado é provavelmente o Git, por causa de diversas funcionalidades específicas e duma boa velocidade de resposta, mesmo em projetos grandes. O plugin para o Eclipse EGit constitui uma interface prática para usar o Git.
GitHub (2008) - Atualmente é o maior repositório de código fonte do mundo. Usa o Git e está acessível na Web. Tem mais de 21 milhões de projetos instalados, embora nem todos estejam ativos.
Detalhes sobre o Git - Todos os participantes dum projeto possuem a sua cópia local do projeto e de todo o código. Trabalham localmente sobre o código e periodicamente usam os comandos do Git para atualizar o estado do projeto local. Sempre que um participante considerar conveniente, dá o comando que incorpora no projeto central as alterações entretanto introduzidas no projeto local. Eis alguns exemplos de comandos:
git clone https://user@github.com/Project/project.git git status git add myfile git commit git push
Exemplos: Eclipse, Visual Studio .Net, Anjuta, Code::Blocks.
Os IDEs mais sofisticados são estendíveis através de plugins. Isso permite que o mesmo sistema possa ser usado para trabalhar em diversas linguagens.
Para quem gosta de ferramentas simples mas que ajudam a produzir trabalho, o Geany é uma excelente alternativa. Trata-se essencialmente dum editor de texto orientado para escrita de programa e que conhece a sintaxe de dezenas de linguagens de programação. Mas a parte mais interessante é ter menus configuráveis e podermos associar comandos a esses menus (por exemplo, podemos invocar o Makefile do nosso projeto.)