Como o seu objetivo real parece ser o de automatizar tudo o que precisa ser feito para executar seu programa, sugiro uma abordagem diferente. Em vez de escrever um script de shell, você pode usar um makefile . Se quiser, você pode escreva uma regra em seu makefile para executar seu executável depois que ele for construído. Você terá então dois arquivos - seu arquivo de código-fonte C ++ e seu makefile - e você poderá executar um único comando com eficiência:
- Cria ou recria seu programa C ++, se e somente se necessário .
- Executa seu programa.
As seções seguintes desta postagem explicam porque você não pode chamar um arquivo .cpp
diretamente (mas deve criar um executável a partir dele primeiro); como instalar o make
, como usá-lo e o que ele está fazendo nos bastidores; e como evitar armadilhas comuns. Mas, caso você queira ter uma ideia de como essa abordagem se parece antes de se aprofundar, você executará make run
depois de colocar isso 0 em Makefile
:
all: myProg
run: all
./myProg
Eu gosto disso melhor para este propósito do que um shell script, e eu acho que você também pode.
Antecedentes
Ao contrário de alguns idiomas interpretados como o Python e o Bash, o C ++ é um linguagem compilada . 1 Os programas escritos em C ++ devem ser construído antes de serem executados. (Building também é algumas vezes chamado de compilação , apesar de compilar mais apropriadamente se referir a uma das etapas de construção.) Você não pode executar um C ++ source code ; em vez disso, ele deve ser compilado no código do objeto 2 , neste case linguagem de máquina . Os arquivos de objetos devem ser vinculados e, mesmo que haja apenas um, ele ainda deve estar vinculado a qualquer bibliotecas compartilhadas que ele usa. A vinculação produz um executável que pode ser executado.
Em suma, você tem que construir seu programa antes de executá-lo, pela primeira vez . Antes de execuções subseqüentes, ele não precisa ser re construído, a menos que você tenha alterado o código-fonte. Nesse caso, você deve compilá-lo novamente se quiser que as alterações sejam refletidas no programa executado. O utilitário make
foi projetado especificamente para esse tipo de situação, em que se deseja executar ações condicionalmente dependendo se ou não, e quando, eles já foram feitos.
Obtendo make
Você pode já ter o comando make
instalado; tente executá-lo para descobrir. Se estiver instalado, você verá algo como:
$ make
make: *** No targets specified and no makefile found. Stop.
Para conseguir, você pode instalar o make pacote , mas eu sugiro instalar build-essential que fornece várias outras ferramentas úteis. (Você pode ter instalado build-essential para obter g++
, que é uma maneira que você já pode tem make
.) Você pode usar o Centro de Software para instalá-lo ou executar o comando:
sudo apt-get update && sudo apt-get install build-essential
make
sem um Makefile
Para ver como make
funciona, sugiro executá-lo sem um makefile primeiro, passando o nome de base do seu arquivo de código-fonte:
$ make myProg
g++ myProg.cpp -o myProg
$ ./myProg
Salam! World
Em execuções subseqüentes, make
compara os registros de data e hora de modificação ( mtime s) nos arquivos de entrada e saída, e não irá reconstruir seu programa desnecessariamente:
$ make myProg
make: 'myProg' is up to date.
Quando você altera myProg.cpp
, isso atualiza seu registro de data e hora de modificação, portanto, make
saberá recriá-lo. (Você também pode atualizar o registro de data e hora de um arquivo com o comando touch
, se você precisa ou quer forçar qualquer arquivo de saída dependendo dele para ser reconstruído E, claro, a exclusão dos arquivos de saída também garantirá que eles sejam reconstruídos quando você executar make
- apenas não exclua o arquivo errado!)
$ touch myProg.cpp
$ make myProg
g++ myProg.cpp -o myProg
Como o make
sabe o que fazer quando você executa make myProg
?
- O argumento
myProg
para make
é chamado de destino .
- Os destinos geralmente são, mas nem sempre, os nomes dos arquivos a serem criados. Os alvos podem ser definidos explicitamente em um makefile.
- Quando um alvo não é definido no makefile ou (como neste caso) não há makefile,
make
procura por arquivos de entrada (ou seja, código-fonte) nomeados de forma a sugerir que eles são destinados à construção o alvo.
-
make
infere qual utilitário e sintaxe usar na construção de um arquivo a partir de seu sufixo (neste caso, .cpp
).
Tudo isso pode ser personalizado, mas em casos simples como este, muitas vezes não precisa ser.
Criando um Makefile para automatizar a criação e a execução do seu programa
Para automatizar tarefas mais complexas do que criar um programa a partir de um único arquivo de código-fonte, como se houvesse vários arquivos de entrada ou (mais aplicável a suas necessidades imediatas) ações que você deseja executar além do compilador, crie um makefile para definir metas para make
e especificar como elas dependem de outros destinos.
O primeiro alvo definido em um makefile é o destino padrão: é o que make
tenta construir quando executado sem argumentos de linha de comando (ou seja, quando você executa apenas make
e não algo como make myProg
).
A maneira usual de usar makefiles é criar um diretório contendo todos os arquivos de código-fonte (e quaisquer outros arquivos) usados para construir seu programa, bem como o makefile, que geralmente é chamado de Makefile
. Com esse nome, make
irá encontrá-lo automaticamente.
Para criar um makefile você pode usar para executar myProg
e isso irá construí-lo automaticamente quando necessário, coloque myProg.cpp
no diretório novo, caso contrário, vazio. Crie outro arquivo de texto nesse diretório chamado Makefile
.
Você pode usar qualquer editor de texto para isso, mas a receita de uma regra - os comandos listados abaixo que serão executados para criar o destino - deve ser recuada com guias em vez de espaços . 3 Então, se o seu editor de texto está atualmente configurado para recuar com espaços quando você pressiona Tab , você deve mudar isso.
Por exemplo, em Gedit ou Pluma, você entra em Editar & gt; Preferências , clique na guia Editor e certifique-se de que Inserir espaços em vez de guias esteja desmarcado:
Muitos editores adotam o padrão de recuar nas guias e não nos espaços, portanto, se você não alterou essa configuração antes, ela já pode estar definida corretamente para os makefiles.
Quando você estiver no seu editor e (se necessário) configurado para recuar com guias, coloque isso em:
all: myProg
run: all
./myProg
Se você copiar e colar isto, estará errado porque os espaços serão copiados mesmo que o seu editor de texto não os faça quando você pressionar Tab . (Isso tem a ver com a maneira como o Ask exibe código do Ubuntu.) Mas você pode simplesmente remover os quatro espaços anteriores a ./myProg
e pressionar a tecla Tab para criar uma tabulação em seu lugar.
Alguns editores de texto têm como padrão mostrar uma guia como 8 espaços ou algum outro número. Tudo bem.
O que esse Makefile faz e como usá-lo
Use o comando:
-
make
, para construir o programa, a menos que já esteja compilado e o executável esteja atualizado com o código-fonte. Ou
-
make run
, para executar o programa, construindo primeiro se necessário (ou seja, se não houver nenhum executável atual).
Este makefile define dois alvos: all
e run
.
-
A meta all
não tem receita própria, mas depende da meta myProg
. Esse destino não é explicitamente definido, portanto, ele diz implicitamente que make
tenta criar myProg
de qualquer arquivo de código-fonte disponível no diretório atual. (Veja a seção make
sem um Makefile acima para detalhes.)
Como all
é o primeiro destino explicitamente definido em Makefile
, ele será criado quando make
for executado no diretório em que Makefile
reside. Assim, configuramos as coisas, então executar make
por si só equivale a executar make all
.
-
O run
target executa o programa. Sua receita consiste no comando que faz isso, ./myProg
. run
declara a all
alvo como uma dependência. Isso faz com que, quando você executar make run
, myProg
seja recriado se o executável myProg
atual não for atual (ou ainda não existir).
Poderíamos também fazer com que run
dependesse de myProg
em vez de all
, mas ainda assim teríamos necessário o all
target explícito (ou uma meta equivalente de um nome diferente) para evitar run
de ser o alvo padrão. Claro, se você quer que o seu programa construa e execute mesmo quando você executa make
, você pode fazer isso.
Outro benefício de depender da meta all
é no caso de ocorrerem mais ações que devem ser tomadas antes que seu programa seja executado. Você pode adicionar uma receita à regra para all
.
Usar o makefile para executar o programa se parece com isso, se precisar ser criado:
$ cd myProg/
$ make run
g++ myProg.cpp -o myProg
./myProg
Salam! World
Ou isso, se não precisar ser criado:
$ make run
./myProg
Salam! World
E se você quiser apenas ter certeza de que o programa foi criado (desde que o arquivo de código-fonte foi modificado pela última vez) sem executar o programa , simplesmente execute make
sem argumentos:
$ make # Here, I run make and myProg isn't current.
g++ myProg.cpp -o myProg
$ make # Running "make" again after "make" or "make run" does nothing.
make: Nothing to be done for 'all'.
( make myProg
ainda funcionará também.)
Um refinamento: sinalizadores personalizados do compilador
make
é uma ferramenta extremamente poderosa, útil para propósitos simples como este, mas também adequada para projetos grandes e complexos. A tentativa de detalhar tudo o que você pode fazer com make
seria um livro inteiro (especificamente, este ).
Mas me ocorreu que você pode querer ver avisos do compilador, quando algo não impede a conclusão da construção, mas ainda é um erro potencial. Estes não vão pegar todos os bugs nos programas que você escreve, mas eles podem pegar muitos.
Ao usar o GCC (como acontece com o comando g++
), recomendo passar pelo menos -Wall
para o compilador. Isso realmente não habilita todos avisos, mas você pode habilitar a maior parte do restante com -Wextra
. Às vezes, você também pode querer -pedantic
. (Veja man gcc
e 3.8 Opções para solicitar ou suprimir avisos no Manual de referência do GCG .)
Para invocar g++
manualmente com esses sinalizadores, você executaria:
g++ -Wall -Wextra -pedantic -o myProg myProg.cpp
Para fazer com que make
invoque o compilador C ++ ( g++
) com os sinalizadores -Wall
, -Wextra
e -pedantic
, adicione uma linha CXXFLAGS=
com eles ao início de Makefile
.
CXXFLAGS=-Wall -Wextra -pedantic
all: myProg
run: all
./myProg
Mesmo que myProg
exista e seja mais recente que myProg.cpp
, a execução de make
ou make run
após a edição de Makefile
continuará criando o programa novamente, porque Makefile
é agora mais recente que myProg
. Isso é bom, porque:
- Nesse caso, a reconstrução do executável faz com que você veja avisos se houver algum (não deveria haver, para esse programa específico).
- Mais geralmente, às vezes, quando você edita um makefile, é porque deseja que diferentes arquivos sejam produzidos ou que sejam produzidos com diferentes conteúdos. (Por exemplo, se você tivesse adicionado o sinal
-O3
para otimizações pesadas ou -g
para fazer o compilador gerar símbolos de depuração, o executável myProg
resultante seria diferente.)
Leitura Adicional
Notas
0 : recomendo ler mais para ver como fazer isso funcionar. Mas no caso de você querer tentar primeiro você mesmo: você deve recuar linhas com abas em vez de espaços.
1 : Estritamente falando, virtualmente qualquer linguagem de programação pode ser interpretada ou compilada dependendo do que implementações para isso foram escritas. Para alguns idiomas, ambos os interpretadores e compiladores existem. Entretanto, o C ++ interpretado é incomum - embora não seja conhecido .
2 : dividindo o edifício em compilando e ligando , e chamando a tradução de um arquivo de código-fonte C ++ (.cc / .cpp / .cxx / .C) no código de objeto compilação , não é toda a história. Programas em C e C ++ (e algumas outras linguagens) são os primeiros pré-processados . Em seu programa, o pré-processador C substitui #include<iostream>
pelo conteúdo do arquivo de cabeçalho <iostream>
antes do início da compilação real. E, no sentido mais restrito, a compilação converte o código-fonte em linguagem assembly em vez de código-objeto.Muitos compiladores (como o GCC / g++
) podem combinar compilação e montagem em uma única etapa e não produzem código assembly a menos que sejam solicitados a fazê-lo.
Enquanto o pré-processamento é uma etapa separada, o GCC e outros compiladores executam automaticamente o pré-processador. Da mesma forma, eles podem executar automaticamente o vinculador, e é por isso que toda a seqüência de pré-processamento , compilação , montagem e ligação é às vezes chamado de "compilação" em vez de "construção". (Observe também que o edifício pode conter mais do que essas etapas - por exemplo, pode envolver a geração de arquivos de recursos, executando um script para configurar como as coisas será construído , etc.)
3 : Você só precisa recuar com guias no makefile propriamente dito. Usar um makefile não impõe nenhum requisito ao modo como você escreve seus próprios arquivos de código-fonte C ++. Sinta-se à vontade para mudar o recuo de abas para espaços quando estiver trabalhando em outros arquivos. (E se você realmente não gostar de recuar com guias em um makefile, você pode definir o .RECIPEPREFIX
variável especial .