Eu sou novo em programação Bash. Quero chamar meu programa C++ no arquivo Bash.
Meu programa é myProg.cpp
:
#include<iostream>
using namespace std;
int main()
{
cout<<"Salam! World"<<endl;
return 0;
}
E meu arquivo bash é myBash.sh
. Como posso chamar meu programa .cpp acima em myBash.sh
arquivo?
Responder1
Você precisa compilá-lo primeiro: primeiro altere o diretório de trabalho atual do Terminal para o caminho do seu arquivo fonte:
cd <path_to_cpp_file>/
Em seguida, compile o arquivo fonte:
g++ myProg.cpp -o myProg
Então você pode chamar o executável compilado do seu bash
script assim:
#!/bin/bash
# ...
<path_to_compiled_executable>/myProg
# ...
Responder2
Desde o seuobjetivo realparece ser 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 umarquivo make.Se desejar, você pode escrever uma regra em seu makefile para executar seu executável depois de compilado. Você terá então dois arquivos - seu arquivo de código-fonte C++ e seu makefile - e poderá executar um único comando com eficiência:
- Constrói ou reconstrói seu programa C++,se e somente se necessário.
- Executa seu programa.
As seções subsequentes desta postagem explicam por que você não pode chamar um .cpp
arquivo diretamente (mas deve primeiro criar um executável a partir dele); como instalar make
, como usá-lo e o que ele faz nos bastidores; e como evitar armadilhas comuns. Mas caso você queira ter uma ideia de como é essa abordagem antes de se aprofundar, você correrá make run
depois de colocar isso0em Makefile
:
all: myProg
run: all
./myProg
Eu gosto mais disso para esse propósito do que de um script de shell, e acho que você também pode gostar.
Fundo
Ao contrário de algunslinguagens interpretadascomo Python e Bash, C++ é umlinguagem compilada.1Os programas escritos em C++ devem serconstruídoantes de serem executados. (Edifício também é às vezes chamadocompilando, no entantocompilandomais apropriadamente refere-se a uma das etapas de construção.) Você não pode executar um C++Código fontearquivo; em vez disso, deve ser compilado emcódigo objeto2, nesse casolinguagem de máquina. Os arquivos objeto devem então ser vinculados entre si e, mesmo que haja apenas um, ele ainda deve ser vinculado a qualquerbibliotecas compartilhadasele usa. A vinculação produz umexecutávelque pode ser executado.
Resumindo, você precisa construir seu programa antes de executá-lo,a primeira vez. Antes das execuções subsequentes não é necessárioréconstruído, a menos que você tenha alterado seu código-fonte; nesse caso, você deverá compilá-lo novamente se quiser que suas alterações sejam refletidas no programa que é executado.A make
utilidadefoi projetado especificamente para esse tipo de situação, onde se deseja realizar açõescondicionalmentedependendo se já foram feitas ou não e quando.
Recebendomake
Talvez você já tenha o make
comando instalado; tente executá-lo para descobrir. Se estiver instalado, você verá algo como:
$ make
make: *** No targets specified and no makefile found. Stop.
Para obter o make você pode instalar ofazer pacote, mas sugiro instalaressencial para construção que fornece uma série de outras ferramentas úteis. (Você pode ter instaladoessencial para construção para obter g++
, que é uma maneira que você já deve ter 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 Makefile
Para ver como make
funciona, sugiro executá-lo primeiro sem um makefile, passando a ele o nome base do seu arquivo de código-fonte:
$ make myProg
g++ myProg.cpp -o myProg
$ ./myProg
Salam! World
Nas execuções subsequentes, make
compara os carimbos de data/hora da modificação (mtimes) nos arquivos de entrada e saída e não reconstruirá seu programa desnecessariamente:
$ make myProg
make: 'myProg' is up to date.
Quando você altera myProg.cpp
, isso atualiza seu carimbo de data/hora de modificação, então make
saberá como reconstruí-lo. (Você também pode atualizar o carimbo de data/hora de um arquivo com otouch
comando, se você precisar ou quiser forçar a reconstrução de qualquer arquivo de saída dependendo dele. E, claro, excluir os 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 você make
sabe o que fazer quando corre make myProg
?
- O
myProg
argumento paramake
é chamado dealvo. - Os alvos são frequentemente, mas nem sempre, os nomes dos arquivos a serem criados. Os alvos podem ser definidos explicitamente em um makefile.
- Quando um alvo não está 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 se destinam à construção do alvo. make
infere qual utilidade e sintaxe usar na construção de um arquivo a partir de seu sufixo (neste caso,.cpp
).
Tudo isso pode ser customizado, mas em casos simples como esse muitas vezes não é necessário.
Criando um Makefile para automatizar a construção e execução do seu programa
Para automatizar tarefas mais complexas do que construir um programa a partir de um único arquivo de código-fonte, como se houver vários arquivos de entrada ou (mais aplicável às suas necessidades imediatas) ações que você deseja realizar além de executar o compilador, você pode criar um makefile para definir alvos para make
e especificar como eles dependem de outros alvos.
O primeiro alvo definido em um makefile é o alvo 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
. Por esse nome, make
você o encontrará automaticamente.
Para criar um makefile que você pode usar para executar myProg
e que irá construí-lo automaticamente primeiro quando necessário, coloque myProg.cpp
em um novo diretório, 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 para uma regra - os comandos listados abaixo dela que serão executados para definir seu destino - deve ser indentada comguiasem vez deespaços.3Portanto, se o seu editor de texto estiver configurado para recuar espaços quando você pressionar Tab, você deverá alterar isso.
Por exemplo, no Gedit ou Pluma, você entrariaEditar > Preferências, Clique noeditorguia e certifique-seInsira espaços em vez de tabulaçõesestá desmarcado:
Muitos editores usam como padrão o recuo com tabulações e não espaços, portanto, se você não alterou essa configuração antes, ela já pode estar definida corretamente para makefiles.
Quando estiver em seu editor e (se necessário) configurado para recuar com tabulações, coloque isto em:
all: myProg
run: all
./myProg
Se você copiar e colar isso, estará erradoporque os espaços serão eliminados mesmo que o seu editor de texto não os crie quando você pressionar Tab. (Isso tem a ver com a maneira como o Ask Ubuntu exibe o código.) Mas você pode simplesmente remover os quatro espaços anteriores ./myProg
e pressionar Tabpara criar uma guia em seu lugar.
Alguns editores de texto mostram uma tabulação com 8 espaços ou algum outro número. Isso é bom.
O que esse Makefile faz e como usá-lo
Use o comando:
make
, para compilar o programa, a menos que ele já esteja compilado e o executável seja atual para o código-fonte.Ou,make run
, para executar o programa,construí-lo primeiro, se necessário(ou seja, se não houver nenhum executável atual).
Este makefile define dois alvos: all
e run
.
O
all
alvo não tem receita própria, mas depende domyProg
alvo. Este destino não é definido explicitamente, portanto, diz implicitamentemake
para tentar construirmyProg
a partir de quaisquer arquivos de código-fonte disponíveis para ele no diretório atual. (Veja omake
Sem Makefileseção acima para obter detalhes.)Como
all
é o primeiro destino definido explicitamente emMakefile
, ele será construído quandomake
for executado a partir do diretório em queMakefile
reside. Assim, configuramos as coisas para que corrermake
por si só seja equivalente a corrermake all
.O
run
alvo executa o programa. Sua receita consiste no comando que faz isso,./myProg
.run
declara oall
alvo como uma dependência. Isso faz com que, quando você executamake run
,myProg
seja reconstruído se o executável atualmyProg
não for atual (ou ainda não existir).Poderíamos muito bem ter feito
run
depend onmyProg
em vez de onall
, mas ainda precisaríamos doall
alvo explícito (ou um alvo equivalente com um nome diferente) para evitarrun
que fosse o alvo padrão. Claro, se você quiser que seu programa seja construídoe corramesmo quando você corremake
sozinho, você pode fazer isso.Outro benefício de depender do
all
alvo é caso mais tarde haja mais ações que devem ser tomadas antes que seu programa seja executado. Você poderia então adicionar uma receita à regra paraall
.
Usar o makefile para executar o programa fica assim, se precisar ser compilado:
$ cd myProg/
$ make run
g++ myProg.cpp -o myProg
./myProg
Salam! World
Ou isto, se não precisar ser construído:
$ make run
./myProg
Salam! World
E se você quiser apenas ter certeza de que o programa foi compilado (desde que o arquivo do 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 de compilador personalizados
make
é uma ferramenta extremamente poderosa, útil para propósitos simples como este, mas também adequada para projetos grandes e complexos. Tentar detalhar todas as coisas que você pode fazer make
daria 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 compilação, mas ainda é um erro em potencial. Eles não detectarão todos os bugs dos programas que você escreve, mas poderão detectar muitos.
Ao usar o GCC (como acontece com o g++
comando), recomendo passar pelo menos -Wall
para o compilador. Na verdade, isso não permitetodosavisos, mas você pode ativar a maior parte do restante com -Wextra
. Às vezes você também pode querer -pedantic
. (Verman gcc
e3.8Opções para solicitar ou suprimir avisosnoManual de referência do GCC.)
Para invocar g++
manualmente com esses sinalizadores, você executaria:
g++ -Wall -Wextra -pedantic -o myProg myProg.cpp
Para make
invocar o compilador C++ ( g++
) com os sinalizadores -Wall
, -Wextra
e -pedantic
, adicione uma CXXFLAGS=
linha com eles no topo de Makefile
.
CXXFLAGS=-Wall -Wextra -pedantic
all: myProg
run: all
./myProg
Mesmo que myProg
ainda exista e seja mais recente que o myProg.cpp
, a execução make
ou make run
após a edição Makefile
ainda criará o programa novamente, porque Makefile
agora é mais recente que o myProg
. Isso é bom porque:
- Nesse caso, reconstruir o executável faz com que você veja avisos, se houver algum (não deveria haver, para aquele programa específico).
- De forma mais geral, às vezes quando você edita um makefile é porque você deseja que arquivos diferentes sejam produzidos ou que sejam produzidos com conteúdos diferentes. (Por exemplo, se você tivesse adicionado o
-O3
sinalizador para otimizações pesadas ou-g
para fazer o compilador gerar símbolos de depuração, omyProg
executável resultante seria diferente.)
Leitura adicional
- Exercício 2: Faça seu Python agoraemAprenda C da maneira mais difícilporZed Shaw.
- OManual de criação do GNU, especialmente2.1Qual é a aparência de uma regra.
- Um tutorial simples de MakefileporBruce A. Maxwell, para obter informações sobre outras maneiras de usar
make
. - "Usando Makefiles" (p. 15) e "Makefiles vs. Shell Scripts" (p. 62) emSéculo 21 CporBen Klemens. Os números das páginas são da primeira edição. (A segunda edição provavelmente é melhor, mas só tenho a primeira edição.)
Notas
0: Recomendo ler mais para ver como fazer isso funcionar. Mas caso você queira tentar primeiro: você deve recuar as linhas com tabulações em vez de espaços.
1: Estritamente falando, praticamente qualquer linguagem de programação poderia ser interpretada ou compilada dependendo do queimplementaçõespois está escrito. Para algumas linguagens, existem intérpretes e compiladores. No entanto, C++ interpretado é incomum - emboranão é inédito.
2: Dividindo o edifício emcompilandoevinculandoe chamando a tradução de um arquivo de código-fonte C++ (.cc/.cpp/.cxx/.C) em código objetocompilando, não é toda a história. Programas em C e C++ (e algumas outras linguagens) são os primeirospré-processado. No seu programa, oPré-processador Csubstitui #include<iostream>
pelo conteúdo do <iostream>
arquivo de cabeçalho antes do início da compilação real. E no sentido mais restrito, a compilação converte o código-fonte emlinguagem assemblyem vez de código objeto. Muitos compiladores (como GCC/ g++
) podem combinar compilação e montagem em uma única etapa e não produzem código assembly a menos que solicitado.
Embora o pré-processamento seja 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 sequência depré-processando,compilação,conjunto, eligaçãoàs vezes é chamado de "compilar" em vez de "construir". (Observe também que a construção pode conter mais do que essas etapas - por exemplo, pode envolver a geração de arquivos de recursos, a execução deum script para configurar como as coisas serão construídas, etc.)
3: Você só precisa recuar com tabulações no próprio makefile. Usar um makefile não impõe nenhum requisito à maneira como você escreve seus próprios arquivos de código-fonte C++. Sinta-se à vontade para mudar o recuo de tabulações para espaços quando estiver trabalhando em outros arquivos. (E se vocêrealmentenão gosta de recuar tabulações em um makefile, você pode definir o.RECIPEPREFIX
variável especial.)
Responder3
Aqui está um exemplo: de myBash.sh
#!/bin/sh
g++ myProg.cpp -o myProg
./myProg