Compilando programas em C++
Neste capítulo, vamos aprender a compilar e executar programas com um único arquivo e projetos na linguagem C++.
No terminal, abra a pasta c_cpp_projects que criamos anteriormente para guardar nossos projetos.
cd ~/dev/c_cpp_projectsPrograma
Seção intitulada “Programa”Crie um diretório chamado binary_tree, entre nele e abra-o no Visual Studio Code.
mkdir -p binary_treecd binary_treecode .Lembre-se de ativar o perfil C/C++ que criamos no capítulo Configurando o VSCode.
Crie um arquivo chamado main.cpp e adicione o seguinte código.
#include <iostream>
using namespace std;
int main(){ cout << "Hello, World!" << endl; return 0;}A estrutura do projeto ficará como a seguir.
Directorybinary_tree
- main.cpp
Para compilar o código, utilizamos o comando clang++, em vez de apenas clang.
A estrutura do comando é a mesma.
Antes de executá-lo, vamos criar uma pasta chamada build para guardar o arquivo binário gerado.
mkdir -p buildclang++ main.cpp -o build/binary_treePara executar o programa, basta chamar o arquivo binário gerado.
./build/binary_tree
Projeto
Seção intitulada “Projeto”Vamos editar este projeto para de fato representar uma árvore binária.
Crie duas pastas dentro do projeto: tree e node.
mkdir -p tree node- Dentro de tree, crie um arquivo
tree.cppe umtree.hpp. - Dentro de node, crie um arquivo
node.cppe umnode.hpp.
touch tree/tree.cpp tree/tree.hpp node/node.cpp node/node.hpp- Na raiz do projeto, crie os arquivos
main.cpp,.clang-formate.clang-tidy.
touch main.cpp .clang-format .clang-tidy- Use os snippets para preencher o conteúdo dos arquivos de formatação e de linting.
A estrutura do projeto deve ficar da seguinte forma.
Directorybuild
- …
Directorynode
- node.cpp
- node.hpp
Directorytree
- tree.cpp
- tree.hpp
- .clang-format
- .clang-tidy
- main.cpp
Copie o conteúdo de todos os trechos de código abaixo para os respectivos arquivos criados. Não se esqueça de salvar cada um deles.
#include "tree/tree.hpp"#include <iostream>
using namespace std;
int main() { Tree tree;
tree.insert(5); tree.insert(3); tree.insert(8); tree.insert(1); tree.insert(4); tree.insert(7); tree.insert(9);
tree.print();
cout << endl;
return 0;}#ifndef __NODE_HPP__#define __NODE_HPP__
class Node {private: int data; Node *left; Node *right;
public: Node(int data); ~Node() {}
int getData(); Node *getLeft(); Node *getRight();
void setData(int data); void setLeft(Node *left); void setRight(Node *right);};
#endif // __NODE_HPP__#include "node.hpp"
Node::Node(int data) { this->data = data; left = nullptr; right = nullptr;}
int Node::getData() { return data;}
Node *Node::getLeft() { return left;}
Node *Node::getRight() { return right;}
void Node::setData(int data) { this->data = data;}
void Node::setLeft(Node *left) { this->left = left;}
void Node::setRight(Node *right) { this->right = right;}#ifndef __TREE_HPP__#define __TREE_HPP__
#include "../node/node.hpp"
class Tree { private: Node *root;
void insert(Node *node, int data); void print(Node *node);
public: Tree(); ~Tree();
void insert(int data); void print();};
#endif // __TREE_HPP__#include "tree.hpp"
#include <iostream>
using namespace std;
Tree::Tree() { root = nullptr;}
Tree::~Tree() { Node *current = root; while (current != nullptr) { Node *temp = current; current = current->getRight(); delete temp; }}
void Tree::insert(int data) { if (root == nullptr) { root = new Node(data); } else { insert(root, data); }}
void Tree::insert(Node *node, int data) { if (data < node->getData()) { if (node->getLeft() == nullptr) { node->setLeft(new Node(data)); } else { insert(node->getLeft(), data); } } else { if (node->getRight() == nullptr) { node->setRight(new Node(data)); } else { insert(node->getRight(), data); } }}
void Tree::print() { print(root);}
void Tree::print(Node *node) { if (node != nullptr) { print(node->getLeft()); cout << node->getData() << " "; print(node->getRight()); }}Antes de compilar o projeto, vamos inicializar o controle de versão com o Git.
Crie o arquivo .gitignore na raiz do projeto, e o preencha com o snippet gitignore-c-cpp.
A estrutura do projeto deve ficar da seguinte forma.
Directorybuild
- …
Directorynode
- node.cpp
- node.hpp
Directorytree
- tree.cpp
- tree.hpp
- .clang-format
- .clang-tidy
- .gitignore
- main.cpp
Então, inicialize o repositório Git e faça o primeiro commit.
git initgit add .git commit -m "Initialize project"Compilação
Seção intitulada “Compilação”Para compilar o projeto, precisamos passar todos os arquivos para o compilador.
Fazemos isso usando o comando clang++ da seguinte maneira:
clang++ <arquivos.cpp> -I <pastas_com_arquivos.hpp> -o <executável><arquivos.cpp>: todos os arquivos.cppdo projeto.<pastas_com_arquivos.hpp>: todas as pastas que contêm arquivos.hppdo projeto.<executável>: nome do arquivo binário gerado.
Ou seja, precisamos especificar a localização de todos os arquivos que desejamos incluir e compilar. Dado que nosso projeto tem mais de uma pasta internamente, precisamos especificar a localização de todas elas. Execute o código a seguir.
mkdir -p buildclang++ tree/tree.cpp node/node.cpp main.cpp -I tree -I node -o build/binary_treePara executar o programa, basta chamar o arquivo binário gerado.
./build/binary_treeSe tudo estiver correto, você verá os nós da árvore binária sendo impressos no terminal em ordem crescente.
Configurações
Seção intitulada “Configurações”Assim como fizemos para projetos em C, podemos configurar tarefas de compilação para C++ no Visual Studio Code. Se você seguiu os passos recomendados no capítulo Configurando o VSCode, já está configurada uma tarefa de compilação para C++.
Infelizmente, essa tarefa apenas compila os arquivos .cpp que estiverem na raiz do projeto.
Uma vez que nosso projeto tem arquivos em pastas diferentes, precisamos especificar a localização de todos eles.
Dessa forma, a tarefa de compilação global não é suficiente para compilar o projeto binary_tree.
Precisamos criar um arquivo de tarefa personalizado para isso.
Nós configuramos alguns snippets para facilitar a construção do arquivo tasks.json.
Crie uma pasta chamada .vscode na raiz do projeto e um arquivo chamado tasks.json dentro dela.
mkdir -p .vscodetouch .vscode/tasks.jsonA estrutura do projeto deve ficar da seguinte forma.
Directory.vscode
- tasks.json
Directorybuild
- …
Directorynode
- node.cpp
- node.hpp
Directorytree
- tree.cpp
- tree.hpp
- .clang-format
- .clang-tidy
- main.cpp
Garanta que o perfil C/C++ esteja ativo e abra o arquivo tasks.json.
Digite nele tasks-json e pressione
Então, dentro do vetor tasks, digite cpp-build-task e pressione
Agora, observe o campo args do arquivo tasks.json.
Ele contém os argumentos que passamos para o comando de compilação.
Atualmente, ele recebe todos os arquivos .cpp que estejam na raiz do projeto.
"args": [ "-fcolor-diagnostics", "-fansi-escape-codes", "-g", "${workspaceFolder}/*.cpp", "-I", "${workspaceFolder}", "-o", "${workspaceFolder}/build/${workspaceFolderBasename}"],Precisamos passar, além desses, todos os arquivos .cpp que estão nas pastas tree e node.
Para isso, adicionamos uma linha para cada pasta.
O atalho ${workspaceFolder} representa a pasta raiz do projeto.
Por isso, cada linha se inicia com ele.
O arquivo tasks.json deve ficar como abaixo.
{ "version": "2.0.0", "tasks": [ { "args": [ "-fcolor-diagnostics", "-fansi-escape-codes", "-g", "${workspaceFolder}/*.cpp", "${workspaceFolder}/node/*.cpp", "${workspaceFolder}/tree/*.cpp", "-I", "${workspaceFolder}", "-o", "${workspaceFolder}/build/${workspaceFolderBasename}" ], "command": "clang++", "detail": "Tarefa de compilação de um projeto em C++. Compila todos os arquivos C++ ligados do projeto em um único executável.", "group": { "kind": "build" }, "label": "Clang: build C++ project (Local)", "options": { "cwd": "${workspaceFolder}" }, "problemMatcher": ["$gcc"], "type": "cppbuild" } ]}Poderemos então usar o atalho Clang: build C++ project (Local).
O Visual Studio Code compilará o projeto e mostrará o resultado no terminal integrado.