Aeca

Capítulo 04 — Build, Run e Executable não são a mesma coisa

Série: Do zero ao jogo comercial com C++ e SFML

Capítulo 04 — Build, Run e Executable não são a mesma coisa
aeca

Do main.cpp ao programa em execução: entendendo o que realmente acontece quando salvamos, construímos e executamos nosso projeto C++

Nos capítulos anteriores começamos nossa jornada com algo extremamente simples:

  #include <iostream>
  int main()
{
    std::cout << "Game Engineering com C++ começou!" << std::endl;
    return 0;
}

Primeiro, fizemos esse código funcionar.

Depois, entendemos sua estrutura.

Em seguida, começamos a quebrá-lo de propósito para aprender a ler erros, formular hipóteses, corrigir problemas e validar o resultado.

Agora existe uma nova pergunta importante.

Quando pressionamos:

  Ctrl + S

alguma coisa acontece.

Quando pressionamos:

  Ctrl + Shift + B

acontece outra coisa.

E quando usamos:

  Ctrl + F5

acontece outra coisa novamente.

Essas ações podem parecer semelhantes quando estamos começando, porque todas fazem parte do mesmo fluxo de desenvolvimento.

Mas elas representam etapas diferentes.

Hoje vamos separar três conceitos fundamentais:

  Save
Build
Run

e entender também um quarto:

  Executable

A ideia central deste capítulo é simples:

salvar não é compilar, compilar não é executar e o executável não é a mesma coisa que o programa em execução.

Essa distinção será essencial quando chegarmos a compilação, linking, DLLs, Debug, Release, automação, testes, CI/CD e distribuição.

1. Nosso projeto continua pequeno

Continuamos com algo conceitualmente próximo de:

  07_Game_Engineering_na_Pratica_CPP_SFML/
│
├── CppGameEngine/
│   └── main.cpp
│
├── README.md
├── CHANGELOG.md
├── CONTRIBUTING.md
└── ROADMAP.md

E nosso código:

  #include <iostream>
  int main()
{
    std::cout << "Game Engineering com C++ começou!" << std::endl;
    return 0;
}

Ainda não temos SFML.

Ainda não temos Engine.

Ainda não temos classes próprias.

Isso é proposital.

Nosso objetivo agora é entender melhor o ciclo de desenvolvimento de um programa C++.

2. Começando pelo Save

Abra main.cpp.

Altere a mensagem:

  std::cout << "Game Engineering com C++ começou!" << std::endl;

para:

  std::cout << "Estamos estudando Build, Run e Executable." << std::endl;

Agora pressione:

  Ctrl + S

O que aconteceu?

O arquivo foi salvo.

Só isso.

Conceitualmente:

  Código no editor
      ↓
   Ctrl + S
      ↓
Arquivo atualizado no disco

Nenhum novo executável precisa ter sido produzido por causa disso.

Nenhum processo precisa ter sido iniciado.

Salvar significa persistir as alterações feitas no arquivo.

3. O código mudou, mas o executável necessariamente mudou?

Não.

Esse ponto é extremamente importante.

Imagine:

  main.cpp antigo
↓
Build
↓
CppGameEngine.exe

Depois alteramos main.cpp:

  main.cpp novo

e apenas salvamos.

Agora podemos ter:

  main.cpp novo

e, ao mesmo tempo:

  CppGameEngine.exe antigo

Ou seja:

o código-fonte atual e o executável existente podem representar momentos diferentes do projeto.

Isso explica situações que confundem muitos iniciantes.

4. “Eu alterei o código, mas continua aparecendo a mensagem antiga”

Imagine que antes tínhamos:

  std::cout << "Mensagem antiga" << std::endl;

Fizemos Build.

Depois alteramos para:

  std::cout << "Mensagem nova" << std::endl;

Salvamos o arquivo, mas executamos diretamente um .exe antigo que ainda não foi reconstruído.

O que poderá aparecer?

  Mensagem antiga

Então pensamos:

“O Visual Studio ignorou meu código.”

Não necessariamente.

O problema pode ser muito mais simples:

  Source atual
≠
Executable atual

Precisamos fazer um novo Build para produzir um artefato correspondente ao código atual.

5. Save não é Build

Vamos formalizar:

Save

  Ctrl + S

significa, de maneira simplificada:

  pegar alterações do editor
        ↓
gravar no arquivo

Build

  Ctrl + Shift + B

significa solicitar que o sistema de build processe o projeto e gere os artefatos necessários.

Conceitualmente:

  Source Code
    ↓
Build
    ↓
Artifacts

Entre esses artefatos poderá existir:

  CppGameEngine.exe

6. O que exatamente é Build?

Até agora tratamos Build como uma caixa-preta.

Fazemos:

  Ctrl + Shift + B

e recebemos:

  Build succeeded.

Mas a palavra Build não significa apenas “compilar uma linha”.

Ela representa um processo maior de construção do software.

Em nosso projeto atual, uma visão bastante simplificada seria:

  main.cpp
   ↓
compilação
   ↓
linking
   ↓
CppGameEngine.exe

Ainda não vamos aprofundar cada estágio.

Isso acontecerá mais adiante.

Por enquanto, queremos apenas entender:

Build é o processo que transforma nosso projeto fonte em artefatos construídos.

7. Artefato?

Em Engenharia de Software, a palavra artifact aparece bastante.

Um artefato é um resultado produzido por algum processo.

No nosso caso, o Build pode produzir coisas como:

  Object Files
Debug Information
Intermediate Files
Executable

Não precisamos conhecer todos ainda.

O mais importante neste capítulo é:

  CppGameEngine.exe

porque ele é algo que conseguimos executar.

8. Faça um Build agora

Com o código atualizado:

  #include <iostream>
  int main()
{
    std::cout << "Estamos estudando Build, Run e Executable." << std::endl;
    return 0;
}

pressione:

  Ctrl + Shift + B

Observe a janela Output.

Se tudo estiver correto:

  Build succeeded.

Agora temos um novo estado.

Conceitualmente:

  main.cpp atualizado
        ↓
      Build
        ↓
CppGameEngine.exe atualizado

9. Mas Build não significa Run

Fizemos Build.

O código foi processado.

O executável foi produzido.

Mas nosso programa necessariamente foi executado?

Não.

Essa distinção é fundamental.

Podemos construir um programa sem iniciá-lo.

Então:

  Build
≠
Run

Build produz.

Run executa.

10. Executando o programa

Agora pressione:

  Ctrl + F5

No Visual Studio, isso normalmente corresponde a iniciar a aplicação sem entrar em uma sessão interativa de debugging.

O resultado deverá ser:

  Estamos estudando Build, Run e Executable.

Agora executamos algo diferente.

Temos:

  Executable
    ↓
Run
    ↓
Processo em execução

Chegamos ao quarto conceito deste capítulo.

11. O que é um executable?

Nosso executável é um arquivo.

No Windows, normalmente possui extensão:

  .exe

No nosso caso:

  CppGameEngine.exe

Ele existe no sistema de arquivos.

Podemos pensar:

  CppGameEngine.exe
│
└── arquivo armazenado no disco

Ele não precisa estar sendo executado para existir.

Podemos ter:

  CppGameEngine.exe

na pasta do projeto durante horas, dias ou meses sem iniciar o programa.

12. O arquivo executável e o programa rodando não são a mesma coisa

Este é um dos conceitos mais importantes do capítulo.

Temos:

  CppGameEngine.exe

como um arquivo.

Quando o sistema operacional inicia esse executável, surge um processo.

Conceitualmente:

  CppGameEngine.exe
        ↓
Sistema operacional inicia
        ↓
Processo
        ↓
Código sendo executado

Portanto:

  Executable
≠
Process

O executável é um arquivo.

O processo representa uma instância em execução daquele programa.

13. Um executável pode gerar mais de um processo

Imagine que futuramente nosso jogo esteja pronto.

Podemos iniciar:

  CppGameEngine.exe

duas vezes.

Dependendo do comportamento permitido pela aplicação, poderíamos ter:

  CppGameEngine.exe
        ↓
Processo A

e novamente:

  CppGameEngine.exe
        ↓
Processo B

O arquivo é o mesmo.

Os processos são instâncias distintas.

Essa diferença será importante quando estudarmos:

  • memória;

  • sistema operacional;

  • debugging;

  • múltiplas instâncias;

  • recursos;

  • IPC;

  • concorrência.

Ainda não precisamos de tudo isso.

Mas a base começa aqui.

14. Onde está nosso .exe?

Agora vamos procurá-lo.

No Visual Studio, estamos utilizando inicialmente:

  Debug
x64

Dependendo de como a solução e o projeto foram criados, o caminho exato pode variar.

Mas você provavelmente encontrará alguma estrutura semelhante a:

  x64/
└── Debug/
    └── CppGameEngine.exe

ou alguma variação equivalente dentro da estrutura da solução/projeto.

Não memorize um caminho sem verificar sua própria configuração.

Procure fisicamente pelo arquivo.

15. Por que eu quero que você procure o executável?

Porque precisamos eliminar uma ideia perigosa:

“O Visual Studio executa meu código C++ diretamente.”

Não é assim que queremos pensar.

Nosso modelo mental deve começar a evoluir:

  main.cpp
   ↓
Build
   ↓
CppGameEngine.exe
   ↓
Sistema operacional
   ↓
Processo

O Visual Studio está ajudando a coordenar essas etapas.

Mas cada conceito existe separadamente.

16. Executando fora do Visual Studio

Depois de encontrar:

  CppGameEngine.exe

feche a execução atual.

Agora tente abrir o executável diretamente pelo Windows Explorer.

Clique duas vezes.

O programa deverá ser iniciado sem que você precise pressionar:

  Ctrl + F5

no Visual Studio.

Esse experimento é extremamente importante.

Ele demonstra que:

o executável existe independentemente da IDE.

O Visual Studio é nossa ferramenta de desenvolvimento.

O programa gerado não “mora dentro” do Visual Studio.

17. O console pode fechar rápido

Ao executar diretamente um pequeno programa de console, você pode perceber que a janela abre e fecha rapidamente.

Nosso programa:

  int main()
{
    std::cout << "Estamos estudando Build, Run e Executable." << std::endl;
    return 0;
}

faz basicamente:

  inicia
  ↓
escreve mensagem
  ↓
return 0
  ↓
termina

Isso acontece muito rápido.

No Visual Studio, determinadas formas de execução podem manter o console visível para facilitar o desenvolvimento.

Não vamos adicionar artifícios desnecessários apenas para manter a janela aberta.

O comportamento de lifetime do processo será estudado no momento apropriado.

18. O programa termina quando main termina?

Em nosso exemplo simples, podemos pensar assim:

  Processo inicia
    ↓
main()
    ↓
std::cout
    ↓
return 0
    ↓
término normal

Mais adiante essa história ficará mais complexa.

Teremos objetos.

Construtores.

Destrutores.

Recursos.

Threads talvez.

Sistemas.

Mas hoje nosso programa praticamente vive durante a execução de main.

19. Vamos observar o processo acontecendo

Existe uma experiência interessante que podemos fazer.

Nosso programa termina rápido demais para ser fácil observá-lo.

Ainda não estudamos input adequadamente, então não vamos complicar o código apenas para isso.

Mas conceitualmente, quando executamos:

  CppGameEngine.exe

o Windows cria um processo.

Podemos observar processos no sistema através do Task Manager / Gerenciador de Tarefas.

Futuramente faremos experimentos mais interessantes com aplicações que permanecem abertas.

Quando tivermos nossa primeira janela SFML, isso ficará visualmente muito mais claro:

  CppGameEngine.exe
        ↓
Processo ativo
        ↓
Janela aberta

20. Código-fonte não precisa existir para o executável rodar

Aqui vem um experimento conceitual importante.

Imagine que construímos:

  CppGameEngine.exe

Depois copiamos apenas esse arquivo para outra pasta.

O executável não precisa abrir main.cpp para executar aquelas instruções.

O código-fonte foi utilizado durante a construção.

Depois temos um artefato executável.

Isso nos leva a:

  Source Code
≠
Executable

Nosso .cpp é entrada do processo de desenvolvimento/build.

O .exe é um resultado construído.

21. “Então posso apagar o código-fonte?”

Tecnicamente, possuir o executável não exige que o código-fonte permaneça ao lado dele para iniciar aquela build.

Mas apagar o código-fonte seria uma péssima ideia porque perderíamos nossa capacidade normal de:

  • entender;

  • alterar;

  • corrigir;

  • reconstruir;

  • versionar;

  • evoluir.

Esse experimento serve apenas para compreender a separação conceitual.

É exatamente por isso que temos:

  source repository

e:

  build artifacts

como responsabilidades distintas.

22. Source Code versus Build Artifact

Podemos classificar:

Source Code

  main.cpp

Código que desenvolvedores escrevem e mantêm.

Build Artifact

  CppGameEngine.exe

Resultado produzido pelo processo de Build.

Futuramente também poderemos ter artefatos como:

  .dll
.lib
.pdb
.zip
installer
test reports

dependendo da evolução do projeto.

Essa terminologia será especialmente importante em CI/CD.

23. O que acontece se alterarmos o source depois do Build?

Vamos experimentar.

Primeiro deixe:

  std::cout << "Build 1" << std::endl;

Faça Build.

Execute.

Resultado:

  Build 1

Agora altere apenas o código para:

  std::cout << "Build 2" << std::endl;

Salve:

  Ctrl + S

Mas não faça Build.

Se você executar manualmente o executável antigo existente no disco, qual mensagem esperamos?

Provavelmente:

  Build 1

porque o executável ainda corresponde ao Build anterior.

Agora faça:

  Ctrl + Shift + B

e execute o artefato novamente.

Esperamos:

  Build 2

Esse experimento prova visualmente a diferença entre:

  source saved

e:

  artifact rebuilt

24. Um pequeno detalhe: a IDE pode construir antes de executar

Aqui precisamos ser cuidadosos.

Ao iniciar o projeto através do Visual Studio, dependendo das configurações e do estado dos arquivos, a IDE pode detectar que o projeto está desatualizado e oferecer ou realizar um Build antes da execução.

Por isso nosso experimento mais claro envolve executar diretamente o .exe antigo.

A ideia não é decorar comportamento específico da IDE.

É entender o princípio:

o executável só muda quando algum processo de Build produz uma nova versão dele.

25. O que significa “out-of-date”?

Durante o desenvolvimento você poderá encontrar mensagens indicando que um projeto está:

  out of date

ou desatualizado.

Conceitualmente:

  Source mudou
     ↓
Artifacts existentes foram gerados antes
     ↓
Projeto precisa ser reconstruído

Ferramentas de build precisam determinar quais partes precisam ser processadas novamente.

Esse assunto ficará muito interessante quando estudarmos incremental builds.

Ainda não precisamos entrar nisso.

26. O Build sempre reconstrói tudo?

Não necessariamente.

Sistemas de build modernos tentam evitar trabalho desnecessário.

Se nada mudou, algumas etapas podem ser consideradas atualizadas.

Você poderá ver mensagens relacionadas a:

  up-to-date

Isso significa, de maneira simplificada, que o sistema concluiu que determinado alvo não precisava ser reconstruído.

Mais tarde estudaremos:

  • incremental build;

  • dependencies;

  • timestamps;

  • build graph;

  • clean;

  • rebuild.

Hoje basta perceber que:

  Build

não significa obrigatoriamente “refazer absolutamente tudo do zero”.

27. Build Solution

Quando usamos:

  Build Solution

estamos solicitando a construção da solution de acordo com suas dependências e configurações.

Hoje nossa solution provavelmente possui apenas:

  1 Project

Então parece simples.

No futuro poderemos ter, por exemplo:

  Solution
├── Engine
├── Game
├── Tools
└── Tests

ou alguma estrutura que surgirá naturalmente.

Nesse cenário, “Build Solution” terá implicações mais interessantes.

Não criaremos esses projetos agora.

28. Configuration também faz parte do Build

Observe a barra superior:

  Debug
x64

Esses dois valores fazem parte do contexto da construção.

Portanto, não existe apenas:

  "o executable"

de maneira abstrata.

Podemos possuir artefatos diferentes para:

  Debug | x64

e:

  Release | x64

Por exemplo:

  x64/Debug/CppGameEngine.exe

e:

  x64/Release/CppGameEngine.exe

Esses dois executáveis podem ser construídos com configurações diferentes.

29. Debug e Release podem gerar executáveis diferentes

Ainda não estudaremos todas as diferenças.

Mas precisamos começar a entender:

  Debug Build
≠
Release Build

Mesmo que ambos produzam:

  CppGameEngine.exe

eles podem ter características diferentes.

Mais adiante veremos diferenças envolvendo:

  • otimização;

  • símbolos de debug;

  • macros;

  • runtime;

  • comportamento;

  • performance;

  • tamanho;

  • diagnósticos.

Isso será extremamente importante quando integrarmos SFML.

30. E x64?

Da mesma forma:

  x64

faz parte da configuração da build.

Uma aplicação construída para:

  x64

não é simplesmente “o mesmo arquivo” que uma build:

  x86

Arquitetura importa.

Mais adiante teremos situações como:

  Application x64
+
Library x64

funcionando corretamente.

Enquanto:

  Application x64
+
Library x86

poderá produzir problemas.

Essa é uma das razões pelas quais estamos aprendendo a olhar configurações desde cedo.

31. Run

Agora vamos isolar o segundo grande conceito.

Run significa iniciar o programa.

Temos:

  Executable
    ↓
Operating System
    ↓
Process

No Visual Studio, usamos:

  Ctrl + F5

para executar sem debugger.

Também existe:

  F5

que normalmente inicia com debugging.

Essas duas ações não são exatamente iguais.

Mas ambas estão relacionadas à execução.

32. Run sem Debugging versus Start Debugging

Vamos estabelecer apenas a distinção inicial.

Ctrl + F5

Conceitualmente:

  Start Without Debugging

Executa a aplicação sem iniciar a sessão normal do debugger.

F5

Conceitualmente:

  Start Debugging

Inicia a aplicação integrada ao debugger.

Ainda não precisamos usar breakpoints.

Mas é importante entender por que existem dois comandos diferentes.

Mais adiante aprenderemos a utilizar:

  breakpoints
step over
step into
watch
call stack
locals
memory

quando realmente tivermos algo interessante para investigar em runtime.

33. Build não exige execução

Imagine uma pipeline no GitHub no futuro.

Ela poderá fazer:

  Checkout
   ↓
Configure
   ↓
Build
   ↓
Tests

Talvez nem exista interface gráfica.

Talvez o objetivo seja apenas verificar:

  "o projeto compila?"

Isso demonstra que Build possui valor independentemente da execução manual do jogo.

34. Run também não significa desenvolvimento

Imagine o jogador final.

Ele receberá algo como:

  Game.exe
Assets/
Dependencies/
Config/

O jogador não precisa:

  Visual Studio
main.cpp
Ctrl + Shift + B

para jogar.

Ele apenas executa o produto distribuído.

Desenvolvimento e execução do produto final são experiências diferentes.

35. Isso nos aproxima da ideia de distribuição

Ainda estamos muito longe de publicar nosso jogo.

Mas já podemos enxergar a sequência:

  Source Code
    ↓
Build
    ↓
Executable + Dependencies + Assets
    ↓
Packaging
    ↓
Distribution
    ↓
User Executes

No fim da série trabalharemos muito mais profundamente com isso.

Hoje estamos aprendendo o primeiro elo.

36. Build directory não é source directory

À medida que o projeto crescer, veremos uma separação entre:

  Source Files

e:

  Generated Files

Essa diferença será importante para Git.

Não queremos versionar indiscriminadamente:

  .exe
.obj
.pdb
build cache
temporary files
IDE files

se eles são reproduzíveis através do Build.

O repositório deve conter principalmente aquilo necessário para reconstruir o projeto.

37. Por que não colocar o .exe no Git?

Para nosso fluxo de desenvolvimento, normalmente não queremos versionar binários gerados em cada Build.

Por quê?

Porque eles:

  • podem ser recriados;

  • mudam frequentemente;

  • são binários;

  • aumentam o repositório;

  • podem depender de configuração;

  • podem ser específicos de plataforma;

  • não mostram diff útil como código-fonte.

Mais tarde poderemos disponibilizar executáveis como:

  Release Artifacts

por meio das Releases do GitHub ou outro canal.

Isso é diferente de versionar cada build no histórico do código.

38. Nosso .gitignore começa a fazer mais sentido

No Capítulo 01 mencionamos que arquivos gerados não devem entrar indiscriminadamente no Git.

Agora temos uma razão mais concreta.

Queremos algo conceitualmente assim:

  Git Repository
├── source code
├── project files
├── documentation
└── configuration necessária

e não necessariamente:

  Git Repository
├── source
├── every .exe
├── every .obj
├── caches
├── local IDE state
└── every generated file

Quando aprofundarmos Git, refinaremos isso.

39. Clean

No Visual Studio existe também a ideia de:

  Clean

O objetivo é remover artefatos produzidos por builds anteriores.

Conceitualmente:

  Source
+
Generated Build Artifacts

depois de Clean:

  Source
+
menos artefatos gerados

Não significa apagar nosso main.cpp.

Esse é um ponto importante.

Clean atua sobre resultados da construção, não sobre nosso código-fonte.

40. Rebuild

Também encontraremos:

  Rebuild

Conceitualmente:

  Clean
+
Build novamente

Em vez de tentar reaproveitar artefatos considerados atualizados, o processo força uma reconstrução mais completa.

Ainda não precisamos usar Rebuild constantemente.

Na realidade, fazer Rebuild para todo problema pode esconder nossa falta de compreensão.

Primeiro queremos entender o que estamos investigando.

41. Build versus Rebuild

Podemos pensar inicialmente:

  Build
│
└── constrói o necessário
  Rebuild
│
├── remove artefatos anteriores
└── constrói novamente

Quando nosso projeto crescer, Rebuild será mais caro.

Imagine:

  Build incremental: 4 segundos
  Rebuild completo: 4 minutos

ou mais em projetos grandes.

Então entender a diferença deixa de ser apenas curiosidade.

Afeta produtividade.

42. Clean, Build e Run são independentes

Podemos ter:

  Clean

sem Run.

Podemos ter:

  Build

sem Run.

Podemos ter um executável já existente e fazer:

  Run

sem novo Build.

Portanto:

  Clean
Build
Run

são operações distintas.

Ferramentas podem encadeá-las automaticamente em alguns contextos, mas isso não apaga suas responsabilidades.

43. Uma analogia simples

Pense em um livro.

Source

O arquivo editável:

  manuscrito

Save

Você grava as mudanças do manuscrito.

Build

Você produz uma versão final diagramada e exportada.

Executable

No nosso caso não é PDF, claro, mas podemos pensar como o artefato final produzido.

Run

Seria “usar” aquele artefato.

A analogia não é perfeita.

Mas ajuda a separar:

  conteúdo fonte

de:

  artefato produzido

44. Outra analogia: receita e bolo

Imagine:

  Receita
↓
Preparação
↓
Bolo

Nosso source é mais próximo da receita.

Build é o processo de transformação.

Executable é o resultado construído.

Run é consumir/iniciar aquele resultado.

Novamente, analogia limitada.

Mas ela ajuda a evitar:

“main.cpp é o programa executável."

Não é.

45. O sistema operacional não executa nosso main.cpp

Quando damos dois cliques em:

  CppGameEngine.exe

o Windows trabalha com o executável.

Ele não abre:

  main.cpp

para interpretar nossas instruções diretamente.

Isso diferencia nosso fluxo C++ de modelos utilizados por algumas outras tecnologias.

Não vamos comparar linguagens profundamente agora.

Mas essa característica é central para compreender C++.

46. “Mas o Visual Studio sabe abrir main.cpp"

Sim.

Porque o Visual Studio é nossa ferramenta de desenvolvimento.

Ele trabalha com:

  source files
project metadata
build configuration
debug configuration

O sistema operacional, ao iniciar nosso produto construído, trabalha com o executável e suas dependências.

Esses papéis são diferentes.

47. Estamos começando a separar Development Time e Runtime

Vamos introduzir duas expressões que serão úteis futuramente.

Development Time

Enquanto estamos construindo o software:

  editar
salvar
compilar
linkar
testar
depurar

Runtime

Enquanto o programa está efetivamente em execução.

Muitos problemas pertencem a momentos diferentes.

Exemplo:

  missing semicolon

é detectado antes de runtime.

Enquanto algo como:

  divisão por zero em determinada condição

pode aparecer durante execução.

Essa distinção continuará crescendo.

48. O executable está parado no disco

Quando nosso jogo não está aberto:

  CppGameEngine.exe

continua sendo apenas um arquivo.

Quando executamos:

  disk
 ↓
loader / operating system
 ↓
memory
 ↓
process

Uma instância do programa passa a existir em memória.

Essa relação nos prepara para um assunto enorme que veremos futuramente:

memória.

49. Arquivo no disco versus dados em memória

Hoje basta pensar:

  Disk
│
└── CppGameEngine.exe
  Memory
│
└── processo em execução

Isso não significa que o executável inteiro simplesmente seja copiado de maneira trivial para RAM.

O sistema operacional faz muito mais que isso.

Mas ainda não precisamos aprofundar loaders, virtual memory, pages ou sections.

Queremos apenas construir a separação conceitual correta.

50. O processo possui estado

Nosso executável armazenado no disco não possui:

  playerHealth atual
playerCoins atual
posição atual
tempo atual da sessão

Esses valores farão sentido quando o programa estiver rodando e possuir estado em memória.

Imagine futuramente:

  CppGameEngine.exe
        ↓
Processo
        ↓
playerHealth = 100
playerCoins = 25
currentDay = 4

Fechamos o processo.

Esses valores em memória desaparecem, a menos que os persistamos em algum lugar.

Isso nos levará, muito mais tarde, a Save/Load.

Percebe como conceitos pequenos se conectam?

51. Executable não contém automaticamente nosso save atual

Nosso .exe representa código e dados necessários ao programa construído.

Run significa iniciar o programa.

Temos:

  Executable
    ↓
Operating System
    ↓
Process

No Visual Studio, usamos:

  Ctrl + F5

para executar sem debugger.

Também existe:

  F5

que normalmente inicia com debugging.

Essas duas ações não são exatamente iguais.

Mas ambas estão relacionadas à execução.

32. Run sem Debugging versus Start Debugging

Vamos estabelecer apenas a distinção inicial.

Ctrl + F5

Conceitualmente:

  Start Without Debugging

Executa a aplicação sem iniciar a sessão normal do debugger.

F5

Conceitualmente:

  Start Debugging

Inicia a aplicação integrada ao debugger.

Ainda não precisamos usar breakpoints.

Mas é importante entender por que existem dois comandos diferentes.

Mais adiante aprenderemos a utilizar:

  breakpoints
step over
step into
watch
call stack
locals
memory

quando realmente tivermos algo interessante para investigar em runtime.

33. Build não exige execução

Imagine uma pipeline no GitHub no futuro.

Ela poderá fazer:

  Checkout
   ↓
Configure
   ↓
Build
   ↓
Tests

Talvez nem exista interface gráfica.

Talvez o objetivo seja apenas verificar:

  "o projeto compila?"

Isso demonstra que Build possui valor independentemente da execução manual do jogo.

34. Run também não significa desenvolvimento

Imagine o jogador final.

Ele receberá algo como:

  Game.exe
Assets/
Dependencies/
Config/

O jogador não precisa:

  Visual Studio
main.cpp
Ctrl + Shift + B

para jogar.

Ele apenas executa o produto distribuído.

Desenvolvimento e execução do produto final são experiências diferentes.

35. Isso nos aproxima da ideia de distribuição

Ainda estamos muito longe de publicar nosso jogo.

Mas já podemos enxergar a sequência:

  Source Code
    ↓
Build
    ↓
Executable + Dependencies + Assets
    ↓
Packaging
    ↓
Distribution
    ↓
User Executes

No fim da série trabalharemos muito mais profundamente com isso.

Hoje estamos aprendendo o primeiro elo.

36. Build directory não é source directory

À medida que o projeto crescer, veremos uma separação entre:

  Source Files

e:

  Generated Files

Essa diferença será importante para Git.

Não queremos versionar indiscriminadamente:

  .exe
.obj
.pdb
build cache
temporary files
IDE files

se eles são reproduzíveis através do Build.

O repositório deve conter principalmente aquilo necessário para reconstruir o projeto.

37. Por que não colocar o .exe no Git?

Para nosso fluxo de desenvolvimento, normalmente não queremos versionar binários gerados em cada Build.

Por quê?

Porque eles:

  • podem ser recriados;

  • mudam frequentemente;

  • são binários;

  • aumentam o repositório;

  • podem depender de configuração;

  • podem ser específicos de plataforma;

  • não mostram diff útil como código-fonte.

Mais tarde poderemos disponibilizar executáveis como:

  Release Artifacts

por meio das Releases do GitHub ou outro canal.

Isso é diferente de versionar cada build no histórico do código.

38. Nosso .gitignore começa a fazer mais sentido

No Capítulo 01 mencionamos que arquivos gerados não devem entrar indiscriminadamente no Git.

Agora temos uma razão mais concreta.

Queremos algo conceitualmente assim:

  Git Repository
├── source code
├── project files
├── documentation
└── configuration necessária

e não necessariamente:

  Git Repository
├── source
├── every .exe
├── every .obj
├── caches
├── local IDE state
└── every generated file

Quando aprofundarmos Git, refinaremos isso.

39. Clean

No Visual Studio existe também a ideia de:

  Clean

O objetivo é remover artefatos produzidos por builds anteriores.

Conceitualmente:

  Source
+
Generated Build Artifacts

depois de Clean:

  Source
+
menos artefatos gerados

Não significa apagar nosso main.cpp.

Esse é um ponto importante.

Clean atua sobre resultados da construção, não sobre nosso código-fonte.

40. Rebuild

Também encontraremos:

  Rebuild

Conceitualmente:

  Clean
+
Build novamente

Em vez de tentar reaproveitar artefatos considerados atualizados, o processo força uma reconstrução mais completa.

Ainda não precisamos usar Rebuild constantemente.

Na realidade, fazer Rebuild para todo problema pode esconder nossa falta de compreensão.

Primeiro queremos entender o que estamos investigando.

41. Build versus Rebuild

Podemos pensar inicialmente:

  Build
│
└── constrói o necessário
  Rebuild
│
├── remove artefatos anteriores
└── constrói novamente

Quando nosso projeto crescer, Rebuild será mais caro.

Imagine:

  Build incremental: 4 segundos
  Rebuild completo: 4 minutos

ou mais em projetos grandes.

Então entender a diferença deixa de ser apenas curiosidade.

Afeta produtividade.

42. Clean, Build e Run são independentes

Podemos ter:

  Clean

sem Run.

Podemos ter:

  Build

sem Run.

Podemos ter um executável já existente e fazer:

  Run

sem novo Build.

Portanto:

  Clean
Build
Run

são operações distintas.

Ferramentas podem encadeá-las automaticamente em alguns contextos, mas isso não apaga suas responsabilidades.

43. Uma analogia simples

Pense em um livro.

Source

O arquivo editável:

  manuscrito

Save

Você grava as mudanças do manuscrito.

Build

Você produz uma versão final diagramada e exportada.

Executable

No nosso caso não é PDF, claro, mas podemos pensar como o artefato final produzido.

Run

Seria “usar” aquele artefato.

A analogia não é perfeita.

Mas ajuda a separar:

  conteúdo fonte

de:

  artefato produzido

44. Outra analogia: receita e bolo

Imagine:

  Receita
↓
Preparação
↓
Bolo

Nosso source é mais próximo da receita.

Build é o processo de transformação.

Executable é o resultado construído.

Run é consumir/iniciar aquele resultado.

Novamente, analogia limitada.

Mas ela ajuda a evitar:

“main.cpp é o programa executável."

Não é.

45. O sistema operacional não executa nosso main.cpp

Quando damos dois cliques em:

  CppGameEngine.exe

o Windows trabalha com o executável.

Ele não abre:

  main.cpp

para interpretar nossas instruções diretamente.

Isso diferencia nosso fluxo C++ de modelos utilizados por algumas outras tecnologias.

Não vamos comparar linguagens profundamente agora.

Mas essa característica é central para compreender C++.

46. “Mas o Visual Studio sabe abrir main.cpp"

Sim.

Porque o Visual Studio é nossa ferramenta de desenvolvimento.

Ele trabalha com:

  source files
project metadata
build configuration
debug configuration

O sistema operacional, ao iniciar nosso produto construído, trabalha com o executável e suas dependências.

Esses papéis são diferentes.

47. Estamos começando a separar Development Time e Runtime

Vamos introduzir duas expressões que serão úteis futuramente.

Development Time

Enquanto estamos construindo o software:

  editar
salvar
compilar
linkar
testar
depurar

Runtime

Enquanto o programa está efetivamente em execução.

Muitos problemas pertencem a momentos diferentes.

Exemplo:

  missing semicolon

é detectado antes de runtime.

Enquanto algo como:

  divisão por zero em determinada condição

pode aparecer durante execução.

Essa distinção continuará crescendo.

48. O executable está parado no disco

Quando nosso jogo não está aberto:

  CppGameEngine.exe

continua sendo apenas um arquivo.

Quando executamos:

  disk
 ↓
loader / operating system
 ↓
memory
 ↓
process

Uma instância do programa passa a existir em memória.

Essa relação nos prepara para um assunto enorme que veremos futuramente:

memória.

49. Arquivo no disco versus dados em memória

Hoje basta pensar:

  Disk
│
└── CppGameEngine.exe
  Memory
│
└── processo em execução

Isso não significa que o executável inteiro simplesmente seja copiado de maneira trivial para RAM.

O sistema operacional faz muito mais que isso.

Mas ainda não precisamos aprofundar loaders, virtual memory, pages ou sections.

Queremos apenas construir a separação conceitual correta.

50. O processo possui estado

Nosso executável armazenado no disco não possui:

  playerHealth atual
playerCoins atual
posição atual
tempo atual da sessão

Esses valores farão sentido quando o programa estiver rodando e possuir estado em memória.

Imagine futuramente:

  CppGameEngine.exe
        ↓
Processo
        ↓
playerHealth = 100
playerCoins = 25
currentDay = 4

Fechamos o processo.

Esses valores em memória desaparecem, a menos que os persistamos em algum lugar.

Isso nos levará, muito mais tarde, a Save/Load.

Percebe como conceitos pequenos se conectam?

51. Executable não contém automaticamente nosso save atual

Nosso .exe representa código e dados necessários ao programa construído.

O progresso do jogador será outro tipo de informação.

Futuramente teremos algo como:

  Game Executable
+
Assets
+
Configuration
+
Save Data

Cada elemento possui responsabilidade diferente.

Mas precisamos primeiro aprender a separar source, executable e runtime.

52. Um primeiro mapa técnico

Agora podemos representar nossa jornada atual:

  main.cpp
   │
   │ Save
   ▼
arquivo fonte atualizado
   │
   │ Build
   ▼
CppGameEngine.exe
   │
   │ Run
   ▼
Processo em execução
   │
   ▼
std::cout
   │
   ▼
Console

Esse modelo ainda é incompleto.

Mas já é muito melhor que:

  "apertei Play e C++ rodou"

53. Vamos fazer um experimento controlado completo

Vamos usar o que aprendemos.

Comece com:

  #include <iostream>
  int main()
{
    std::cout << "Version A" << std::endl;
    return 0;
}

Passo 1 — Save

  Ctrl + S

Passo 2 — Build

  Ctrl + Shift + B

Passo 3 — Run

  Ctrl + F5

Resultado:

  Version A

Agora altere:

  std::cout << "Version B" << std::endl;

Salve.

Localize e execute manualmente o .exe antigo sem reconstruir.

Observe o resultado.

Depois faça novo Build.

Execute novamente.

Compare.

Esse experimento deve consolidar a diferença entre as etapas.

54. Verifique o timestamp do arquivo

Outra observação interessante:

localize:

  CppGameEngine.exe

e veja sua data/hora de modificação.

Faça uma alteração real.

Salve apenas.

Observe o executável novamente.

Depois faça Build.

Confira o timestamp.

Essa é mais uma evidência física de que:

  Save

e:

  Build

produzem efeitos diferentes.

55. E se o Build falhar?

Considere:

  std::cout << "Version C" << std::endl

sem:

  ;

Faça Save.

Depois Build.

O Build falha.

O que acontece com nosso executável anterior?

Dependendo do estado da pasta, o executável da última build bem-sucedida pode continuar existindo.

Isso pode produzir uma armadilha.

56. Executable antigo após Build failed

Imagine:

  Build 1
↓
CppGameEngine.exe válido
  Código alterado com erro
↓
Build 2
↓
FAILED

Talvez ainda exista:

  CppGameEngine.exe

da Build 1.

Então alguém pode executá-lo e pensar:

“Mas meu programa está funcionando!”

Na realidade, está executando uma versão anterior.

Isso acontece bastante.

57. Build succeeded importa

Quando fazemos alterações, não basta pressionar o botão e presumir que tudo aconteceu corretamente.

Observe:

  Build succeeded

ou:

  Build failed

A saída do Build faz parte da validação.

Se o Build falhou, você não deve assumir que o executável existente representa o código atual.

58. Essa diferença ajuda no debugging

Imagine:

“Eu corrigi a mensagem, mas continua aparecendo a antiga.”

Perguntas úteis:

  Salvei o arquivo?
↓
O Build realmente foi executado?
↓
O Build terminou com sucesso?
↓
Estou executando o .exe correto?
↓
Estou na configuração correta?
↓
Estou executando Debug ou Release?
↓
Existe outro executável em outra pasta?

Observe como conhecer o processo muda nossa investigação.

59. “Estou executando o executable correto?”

Essa pergunta será extremamente importante quando tivermos:

  Debug/
└── Game.exe
  Release/
└── Game.exe

Talvez você atualize Debug e execute manualmente Release.

Ou o contrário.

Ambos podem possuir o mesmo nome:

  Game.exe

mas representar builds diferentes.

Por isso path e configuração importam.

60. O mesmo nome não significa o mesmo arquivo

Considere:

  x64/Debug/CppGameEngine.exe

e:

  x64/Release/CppGameEngine.exe

Os dois nomes finais são:

  CppGameEngine.exe

Mas os caminhos são diferentes.

Portanto, são arquivos diferentes.

Esse princípio vale para muitos recursos no desenvolvimento.

Contexto importa.

61. Build Configuration é parte do diagnóstico

Quando futuramente pedirmos ajuda para um problema, não basta dizer:

“Estou rodando o jogo.”

Precisamos talvez informar:

  Visual Studio 2022
C++20
Debug
x64
MSVC

Por quê?

Porque o comportamento pode variar por configuração.

Em alguns bugs teremos:

  Debug works
Release fails

Essa diferença será um sinal extremamente importante.

62. Build e Run também são separados em CI/CD

No futuro, uma pipeline poderá fazer:

  Checkout
   ↓
Build Debug
   ↓
Run Tests
   ↓
Build Release
   ↓
Package

Observe:

  Build

e:

  Run Tests

são etapas separadas.

Automação deixa essas diferenças ainda mais explícitas.

63. Um jogo comercial precisa de builds reproduzíveis

Imagine que publiquemos a versão:

  1.0.0

Se um bug grave aparecer, precisamos saber:

  • qual código produziu aquela build;

  • quais dependências foram utilizadas;

  • qual configuração;

  • qual compilador;

  • quais assets;

  • qual versão;

  • qual artefato foi distribuído.

Por isso Build Engineering é uma disciplina séria.

Estamos apenas dando o primeiro passo.

64. O .exe não é necessariamente suficiente

Hoje nosso pequeno programa provavelmente executa com poucas preocupações extras.

Mas quando adicionarmos SFML teremos dependências adicionais.

Podemos chegar a algo como:

  CppGameEngine.exe
+
sfml-graphics-3.dll
+
sfml-window-3.dll
+
sfml-system-3.dll
+
assets

dependendo da forma de integração.

Então descobriríamos rapidamente que:

possuir apenas o .exe nem sempre significa possuir tudo necessário para executar o programa.

Isso será estudado quando integrarmos a biblioteca.

65. Essa é a origem de muitos erros de DLL

Futuramente poderemos encontrar mensagens relacionadas a:

  DLL not found

ou erros de inicialização.

Quando isso acontecer, já saberemos distinguir:

  Source
Build
Executable
Runtime Dependencies
Process

Isso torna o troubleshooting muito mais claro.

66. O que significa “programa”?

A palavra “programa” pode ser utilizada informalmente para várias coisas.

Às vezes alguém diz:

“Meu programa está nesta pasta.”

e aponta para:

  CppGameEngine.exe

Em outro contexto:

“Meu programa travou.”

e está falando do processo em execução.

Ou:

“Estou escrevendo meu programa.”

e está falando do source.

Não precisamos proibir o uso informal.

Mas tecnicamente queremos saber diferenciar:

  source code
build artifacts
executable
process

quando a precisão for necessária.

67. Build não é Compiler

Outra distinção que prepararemos agora:

  Build
≠
Compiler

O compilador é uma ferramenta envolvida no processo.

Build é um processo mais amplo.

Conceitualmente:

  Build
├── preprocessing
├── compilation
├── linking
└── artifact generation

Essa representação ainda é simplificada.

Nos próximos capítulos técnicos aprofundaremos cada etapa.

68. Compiler também não é Linker

Você já viu no Roadmap que estudaremos erros como:

  LNK2019
unresolved external symbol

Esses erros não são simplesmente erros de sintaxe.

Eles surgem em outra etapa.

Por isso precisamos aprender:

  Compiler
≠
Linker

Mas ainda não vamos abrir essa caixa totalmente hoje.

Primeiro precisamos dominar a visão macro.

69. Nossa visão macro agora é esta

  SOURCE
main.cpp
   ↓
BUILD
processo de construção
   ↓
ARTIFACT
CppGameEngine.exe
   ↓
RUN
solicitação de execução
   ↓
PROCESS
programa ativo

Essa sequência é o centro deste capítulo.

70. E onde entra Ctrl + S?

Antes de Build:

  Editor
   ↓
Ctrl + S
   ↓
main.cpp salvo

Então nosso fluxo completo fica:

  Editar
  ↓
Save
  ↓
Source atualizado
  ↓
Build
  ↓
Executable atualizado
  ↓
Run
  ↓
Processo
  ↓
Resultado

Agora começamos a possuir um ciclo de desenvolvimento mais consciente.

71. O ciclo de desenvolvimento atual

Nosso fluxo de trabalho pode ser descrito como:

  EDIT
 ↓
SAVE
 ↓
BUILD
 ↓
RUN
 ↓
OBSERVE
 ↓
MODIFY
 ↓
REPEAT

Em breve adicionaremos:

  DEBUG
TEST

Depois:

  PROFILE
PACKAGE
RELEASE

O ciclo crescerá junto do software.

72. Um erro em cada etapa produz sintomas diferentes

Imagine:

Save

Problema no sistema de arquivos ou permissões.

Build

Erro de compilação ou linking.

Run

Executable inexistente ou problema de inicialização.

Runtime

Crash ou comportamento incorreto.

Portanto, perguntar:

“Em que etapa o problema aconteceu?”

já reduz bastante nosso espaço de investigação.

73. O primeiro passo do troubleshooting agora pode ser

Antes:

  deu erro

Agora:

  O erro aconteceu:
- ao salvar?
- durante Build?
- ao iniciar?
- durante execução?

Essa classificação simples já é extremamente poderosa.

74. Vamos provocar um cenário completo

Use:

  #include <iostream>
  int main()
{
    std::cout << "Stable build" << std::endl;
    return 0;
}

Faça:

  Save
Build
Run

Tudo funciona.

Agora altere para:

  #include <iostream>
  int main()
{
    std::cout << "Broken build" << std::endl
    return 0;
}

Faça Save.

O arquivo foi salvo com sucesso.

Faça Build.

Falha.

Observe:

  Save succeeded
Build failed

São resultados diferentes.

75. O código inválido pode ser salvo normalmente

Esse detalhe é importante.

O editor pode salvar:

  std::cout << "Broken build" << std::endl

mesmo que o código seja inválido para compilação.

O sistema de arquivos não entende C++ nesse nível.

Para ele, main.cpp é um arquivo contendo bytes/texto.

Quem verifica as regras da linguagem durante construção é a toolchain.

Isso demonstra novamente:

  Save
≠
Compile

76. “Salvar” não valida nosso C++

Exatamente.

Ter:

  main.cpp

gravado corretamente no disco não significa:

  C++ válido

nem:

  Build bem-sucedido

nem:

  Programa correto

São níveis diferentes de validação.

77. E Build succeeded não significa software correto

Também precisamos lembrar do capítulo anterior.

Temos:

  Build succeeded

mas talvez:

  Game Logic incorrect

Portanto:

  Save succeeded
≠
Build succeeded

e:

  Build succeeded
≠
Behavior correct

e:

  Behavior correct em um teste
≠
Software completo e correto

É por isso que teremos testes e QA.

78. Um exemplo de game logic

  #include <iostream>
  int main()
{
    std::cout << "Player Coins: 999999" << std::endl;
    return 0;
}

Pode compilar.

Pode executar.

Mas talvez o jogador devesse iniciar com:

  25

O pipeline técnico funcionou.

A regra funcional está errada.

Diferentes camadas de qualidade exigem diferentes formas de validação.

79. Build engineering não substitui testing

Build responde perguntas como:

conseguimos construir este software?

Testes respondem perguntas diferentes:

determinados comportamentos estão corretos?

QA vai ainda mais longe:

o produto atende expectativas de qualidade no contexto real?

Tudo isso aparecerá ao longo da série.

Mas a primeira base é saber o que estamos construindo e executando.

80. Nosso primeiro diagrama completo

Vamos consolidar:

  DEVELOPMENT
                      main.cpp
                       │
                       │ Edit
                       ▼
                    main.cpp
                       │
                       │ Save
                       ▼
               Source persisted
                       │
                       │ Build
                       ▼
              Build system / tools
                       │
                       ▼
               CppGameEngine.exe
                       │
                       │ Run
                       ▼
                Operating System
                       │
                       ▼
                     Process
                       │
                       ▼
                Program behavior

Ainda não representa detalhes de compilação.

Mas já nos dá um mapa.

81. Microdesafio 1 — classifique cada ação

Classifique:

Situação A

Você altera:

  std::cout << "Hello";

e pressiona Ctrl + S.

Resposta esperada:

  Save

Situação B

Você pressiona Ctrl + Shift + B.

Resposta:

  Build

Situação C

Você abre CppGameEngine.exe.

Resposta:

  Run

Situação D

O Windows mostra CppGameEngine.exe no disco.

Resposta:

  Executable / Build Artifact

Situação E

O jogo aparece no Gerenciador de Tarefas.

Resposta:

  Process

82. Microdesafio 2 — encontre a inconsistência

Imagine:

  main.cpp:
"Version 2"
  Executable:
construído ontemÚltimo Build:
failedPrograma executado:
"Version 1"

Existe necessariamente um mistério?

Não.

Uma explicação muito provável:

o executável disponível ainda corresponde à última build bem-sucedida.

Isso é exatamente o tipo de raciocínio que queremos desenvolver.

83. Microdesafio 3 — faça o experimento das versões

Crie:

  #include <iostream>
  int main()
{
    std::cout << "Executable Version 1" << std::endl;
    return 0;
}

Faça:

  Save
Build

Depois altere apenas o source para:

  std::cout << "Executable Version 2" << std::endl;

Faça apenas:

  Save

Execute manualmente o executável anterior.

Depois:

  Build
Run

Observe a diferença.

Não apenas leia este experimento.

Faça.

84. Microdesafio 4 — encontre o executable

Sem usar pesquisa na internet, encontre no seu próprio projeto:

  CppGameEngine.exe

Depois responda:

  Qual configuração gerou este arquivo?
Qual plataforma?
Qual pasta?
Qual horário de modificação?

Esse pequeno exercício começa a treinar familiaridade com nossa build.

85. Microdesafio 5 — explique com suas palavras

Tente explicar sem voltar ao artigo:

Qual a diferença entre Save, Build, Executable, Run e Process?

Uma resposta possível:

Save grava o código-fonte. Build transforma o projeto em artefatos. O executable é um desses artefatos. Run solicita ao sistema operacional que inicie esse executável. O processo é a instância do programa em execução.

Se você consegue explicar isso, o objetivo central do capítulo foi atingido.

86. Precisamos alterar nosso main.cpp permanentemente?

Não necessariamente.

Os textos:

  Version A
Version B
Stable build
Broken build

foram apenas experimentos.

Podemos voltar ao estado simples:

  #include <iostream>
  int main()
{
    std::cout << "Game Engineering com C++ começou!" << std::endl;
    return 0;
}

O aprendizado deste capítulo foi principalmente conceitual e operacional.

87. O projeto ainda não precisa crescer

Nossa arquitetura continua:

  CppGameEngine/
└── main.cpp

Não precisamos criar:

  BuildManager
ExecutableManager
ProcessManager

Isso seria um exemplo perfeito de abstração sem necessidade.

Estamos aprendendo conceitos da toolchain.

Não construindo classes para representar cada substantivo encontrado no artigo.

88. Nem todo conceito precisa virar classe

Essa regra merece ser registrada cedo.

Aprendemos:

  Build
Process
Executable

Isso não significa:

  class Build
{
};

ou:

  class Process
{
};

Arquitetura não é transformar todo termo técnico em objeto.

Classes aparecerão quando houver responsabilidade real que nosso software precise representar.

89. Precisamos de commit?

Se o estado final do código for exatamente o mesmo do capítulo anterior, não precisamos criar commit apenas porque aprendemos novos conceitos.

Mas existe uma possibilidade interessante.

Se neste momento você adicionar ou ajustar um .gitignore para impedir que artefatos de build e arquivos locais sejam versionados, isso representa uma mudança real.

Nesse caso, um commit poderia ser:

  git add .gitignore
git commit -m "build: ignore generated Visual Studio files"

Mas somente se o .gitignore realmente foi criado ou alterado.

Não criaremos commits fictícios.

90. E o CHANGELOG?

Também não precisa mudar apenas porque localizamos um .exe.

O CHANGELOG deve refletir alterações reais e relevantes do software.

Aprendizado editorial pertence ao artigo.

Mudanças do código pertencem ao Git.

Essa separação continua válida.

91. O ROADMAP mudou?

O Capítulo 04 é parte da jornada educacional.

Nosso ROADMAP técnico possui itens relacionados à fundação e, mais adiante, ao processo de compilação/linking.

Só devemos marcar itens como concluídos quando realmente atingirmos o objetivo técnico descrito.

Por exemplo, entender conceitualmente Build não significa necessariamente concluir toda a fase de compilação e linking.

Ainda existe bastante coisa pela frente.

92. Onde estamos no Roadmap educacional?

Até aqui:

  Capítulo 00
↓
Visão da jornada
  Capítulo 01
↓
Primeiro programa C++Capítulo 02
↓
Anatomia do códigoCapítulo 03
↓
Erros e troubleshootingCapítulo 04
↓
Save, Build, Executable e Run

Agora temos base suficiente para avançar à programação propriamente dita com dados.

E esse próximo passo é muito importante.

93. Nosso programa ainda não consegue lembrar nada

Observe:

  std::cout << "Player Health: 100" << std::endl;

O número:

  100

está preso dentro de uma string.

Nosso programa não possui uma informação chamada:

  playerHealth

Ele possui apenas texto.

Se quisermos:

  Player toma dano
↓
Health diminui
↓
Nova Health aparece

precisamos de algo que represente aquele dado.

Agora surge um problema concreto.

94. Precisamos armazenar estado

Imagine nosso futuro jogo:

  Player
├── Health
├── Energy
├── Coins
└── Experience

Se essas informações mudarem durante a execução, precisamos armazená-las.

Por exemplo:

  Health
100
↓
leva dano
↓
80

Essa transformação exige algo que ainda não estudamos formalmente.

Variáveis.

95. Agora variáveis têm uma razão para existir

Poderíamos ter começado esta série com:

  int x = 10;

e dito:

“Isso é uma variável.”

Mas agora existe um problema real.

Nosso futuro jogador precisa possuir informações mutáveis.

Então algo como:

  int playerHealth = 100;

começa a fazer sentido.

Observe também nossa convenção:

  playerHealth

utiliza:

  camelCase

porque é uma variável.

E está em inglês.

Estamos começando a usar nossas decisões de nomenclatura em código real.

Conclusão

Neste capítulo separamos conceitos que parecem semelhantes quando começamos a programar.

Aprendemos que:

  Save

grava alterações no arquivo.

Que:

  Build

executa o processo de construção do projeto.

Que:

  CppGameEngine.exe

é um artefato produzido pelo Build.

Que:

  Run

inicia o executável.

E que:

  Process

é uma instância do programa em execução.

Nossa visão evoluiu de:

  "Eu aperto Play e o C++ roda."

para:

  Source
  ↓
Save
  ↓
Build
  ↓
Executable
  ↓
Run
  ↓
Process
  ↓
Behavior

Também aprendemos que:

  Source atualizado
≠
Executable atualizado

se ainda não houve novo Build.

Que um Build falho pode deixar um executável anterior no disco.

Que:

  Debug

e:

  Release

podem produzir builds distintas.

Que:

  x64

faz parte da configuração.

E que o executável armazenado no disco não é a mesma coisa que o processo vivo em memória.

Esses conceitos parecem simples.

Mas eles serão fundamentais quando chegarmos a:

  • compilação;

  • linker;

  • bibliotecas;

  • SFML;

  • DLLs;

  • testes;

  • Debug/Release;

  • CI/CD;

  • packaging;

  • distribuição.

Agora nosso ciclo está mais claro:

  EDIT
 ↓
SAVE
 ↓
BUILD
 ↓
RUN
 ↓
OBSERVE
 ↓
UNDERSTAND
 ↓
EVOLVE

E finalmente podemos começar a fazer nosso programa guardar alguma coisa.

Próximo capítulo

Capítulo 05 — Variáveis: nosso futuro jogo precisa lembrar informações

No próximo artigo deixaremos de imprimir apenas valores fixos como:

  std::cout << "Player Health: 100" << std::endl;

e começaremos a representar dados reais em memória.

Vamos criar algo como:

  int playerHealth = 100;

e entender, passo a passo:

  • o que é uma variável;

  • por que programas precisam armazenar estado;

  • o que significa declarar;

  • o que significa inicializar;

  • o papel do nome;

  • o papel do valor;

  • como ler uma variável;

  • como alterar uma variável;

  • como imprimir seu conteúdo;

  • por que nomes importam;

  • por que utilizaremos camelCase em variáveis;

  • como variáveis começam a representar o estado do nosso futuro jogo.

E finalmente nosso programa poderá sair de:

  "Health: 100"

para algo conceitualmente mais poderoso:

  playerHealth
     ↓
valor atual
     ↓
pode mudar durante a execução

Será o primeiro passo para nosso software começar a possuir estado de verdade.

Subscreve "Aeca" para receber atualizações diretamente na tua caixa de entrada
aeca

Subscreve aeca para reagir

Subscrever

Comentários

Ainda não há comentários. Sê o primeiro a comentar!

Subscreve Aeca para receber atualizações diretamente na tua caixa de entrada