Configurando el entorno de desarrollo

Escrito el Miércoles 24 de Septiembre del 2008 por Ealdor

[A] Introducción

A menos que quieras incrustar las instrucciones en binario en el editor hexadecimal ("¡que lujazo!, cuando eramos jovenes ¡teniamos que cambiar cada bit individualmente con imanes!"), necesitarás un entorno de desarrollo para transformar el código legible humano en lenguaje máquina. Hay bastantes opciones donde elegir, pero la principal en el homebrew (aplicaciones caseras) de la GBA es devkitPro y el compilador multiplataforma ARM devkitARM. Este capítulo te mostrará como configurar los componentes necesarios y la forma de hacerlos funcionar y como compilar código tonc con el. También te mostraré donde puedes encontrar otros paquetes de desarrollo disponibles en la actualidad, pero tanto este capítulo como los otros estarán enfocados al devkitPro/ARM.
La última sección explica algunos detalles sobre el uso de la linea de comandos y los makefiles. Es opcional, pero por razones históricas tengo que cubrirlo antes del resto de capítulos en vez de ponerlo en el apéndice.

[B] DevkitPro y devkitARM

(1) Instalación

Imagen

En los últimos años, devkitPro (DKP) se ha convertido en el conjunto de herramientas estandar para el homebrew en la GBA y está disponible para las plataformas Windows, Mac y Linux. DevkitPro es en realidad un paquete, que contiene, compiladores para unos cuantos sistemas (incluido la GBA), librerías y códigos de ejemplo y un editor. Puedes encontrar la descarga en la sección de descarga de la página de sourceforge: http://sourceforge.net/projects/devkitpro/.
Para la GBA necesitarás:

- DevkitARM (DKA). El compilador multiplataforma ARM, basado en el conjunto de herramientas GCC.
- MSys. Una consola con comandos Unix básicos, como make y rm. Probablemente solo sea necesaria para las plataformas Windows, las cuales generalmente carecen de estas herramientas.

Otros elementos recomendables son:

- Programador Notepad 2: un avanzado editor de texto con resaltado de código, plegado de código y consola de ejecución de comandos. Supongo que podrías llamarlo un mini-IDE. Incluso si tienes tu propio editor, es recomendable que obtengas este también ya que ambos, los ejemplos de DKP y los de TONC, contienen archivos de proyecto PN2, lo cual hace más facil construir (build) los proyectos de la GBA.
- Libgba: un conjunto de tipos básicos, macros y funciones para usar en el desarrollo de la GBA. Si bien no las voy a utilizar, vale la pena hecharles un vistazo. Actualmente libgba y la librería de código de tonc (tonclib) son bastante incompatibles (multiples definiciones y demás), estoy intentando asegurarme de que no haya ningún conflicto entre ellas.
- Ejemplos de GBA: un conjunto de proyectos de ejemplo usando libgba.

Para Windows, hay un instalador que descarga e instala los componentes automaticamente. Para Mac y Linux, tendrás que instalar las cosas tu mismo. El proceso de instalación también crea un número de variables de entorno para los directorios de devkitPro y devkitARM y añade msys/bin a la RUTA (PATH).

Cuando instales DKP en Windows, hay una cosa con la que tienes que tener cuidado. Las herramientas basadas en GCC tienen su origen en Unix, y Unix no tiene la simpatía de usar espacios en las rutas. Por lo tanto no lo instales dentro de un directorio con espacios (como c:\Archivos de Programa) y tampoco pongas tus proyectos en una carpeta con espacios en el nombre (como Mis Documentos). Basicamente, no uses los directorios estandar de Windows. Puedes ver mi arbol de instalación el la imagen de arriba, tengo la costumbre de poner devkitPro dentro de c:\devkitPro.

No uses espacios en la rutas (paths)

GCC hace uso del conjunto de herramientas GCC, las cuales no admiten bien el uso de espacios en las rutas (como Mis Documentos). Los espacios son usados como una separación entre las opciones en la linea de comandos y cuando tienes espacios en las rutas, las herramientas los interpretarán como nuevas opciones. Aunque hay maneras de utilizarlos, te salvaras de muchos dolores de cabeza simplemente no utilizandolos.

(2) Construyendo proyectos con DevkitARM

Imagen

Hay varias maneras de construir los proyectos de GBA, pero el proceso recomendado es usar makefiles. En particular la plantillas de los makefiles de devkitPro. El makefile del proyecto template de la GBA puede encontrarase en $(DEVKITPRO)/examples/gba/template. Cuando crees un nuevo proyecto por ti mismo, básalo en esta plantilla. Se puede ver la estructura básica de la plantilla del proyecto en la imagen de la derecha. El directorio build es donde irán todos los archivos intermedios. Rara vez tendrás que mirar ahí. El directorio source es donde se pone el código fuente: los archivos C, C++ y quizás archivos de ensamblador. Si tienes archivos header, ponlos en el directorio include.
Notese que los directorios build e include en realidad no existen en la plantilla del proyecto; build se crea mediante el proceso de construcción, y ya que no hay cabeceras (headers) que incluir, el directorio include no es necesario en este caso y puede ser eliminado, pero si tienes cabeceras, debes ponerlas ahí.
El directorio de la plantilla tiene dos archivos: el archivo del proyecto PN2, template.pnproj y el Makefile. Una vez que abrás el proyecto en PN2, puedes construir el proyecto con Alt+1, y limpia el proyecto con Alt+2. Si va correcto, deberías obtener algo como esto:

> "make"
template.c
arm-eabi-gcc -MMD -MP -MF /e/dev/devkitPro/examples/gba/template/build/template.d
-g -Wall -O3 -mcpu=arm7tdmi -mtune=arm7tdmi -fomit-frame-pointer -ffast-math
-mthumb -mthumb-interwork -I/e/dev/devkitPro/libgba/include
-I/e/dev/devkitPro/examples/gba/template/build
-c /e/dev/devkitPro/examples/gba/template/source/template.c -o template.o
linking multiboot
built ... template_mb.gba
ROM fixed!

> Process Exit Code: 0
> Time Taken: 00:02

La salida consiste en 6 lineas:

1. 'make'. Invoca make para ejecutar el makefile.
2. 'template.c'. El archivo que estamos compilando.
3. 'arm-eabi-gcc -MMD ...'. Esta es una linea muy larga, se divide en múltiples lineas, que invoca al compilador. gcc es el front-end del compilador, y arm-eabi es el prefijo que devkitARM usa para distinguirlo de todas las otras versiones de gcc. El resto son las opciones del compilador. Basicamente, todo estas cosas transforman el archivo fuente template.c en un archivo objeto llamado template.o.
4. 'linking multiboot'. Despues de la compilación, todos los archivos objetos tienen que ser enlazados juntos en el binario final. La llamada al enlazador está escondida aquí, pero es otra llamada al arm-eabi-gcc con diferentes opciones de configuración. Cubriré que significa "multiboot" despues.
5. 'built ... template_mb.gba'. Indica que todo funcionó bien, y ahora tenemos un binario GBA llamado template_mb.gba.
6. 'ROM fixed!'. Cada ROM de GBA empieza con una cabecera que la GBA chequea para ver si es un programa GBA válido. Si el chequeo de la cabecera falla, la GBA rechazará el programa (aunque los emuladores lo aceptarán). Hay una herramienta llamada gbafix que parchea la ROM con una cabecera válida, que es de lo que trata esta linea.

Imagen
template(_mb).gba.

La linea 'ROM fixed!' significa que la construcción se ha logrado. Deberías tener un archivo template_mb.gba. Cuando abras este archivo en el VBA o no$gba deberías ver algo parecido a la imagen de arriba. Si no ves ningún archivo .gba o al ejecutarlo en el emulador muestra una pantalla en blanco, algo fuera de tu control ha salido mal. Pero antes de llegar a lo que ha salido mal, quiero que le heches un vistazo al archivo Makefile en primer lugar.

Usando otros editores para gestionar proyectos

Programmer's Notepad 2 es solo uno de los muchos editores con los que puedes trabajar. En principio, todo lo que necesitas es un editor capaz de ejecutar herramientas externas como make. DevkitPro's FAQ tiene una perfecta visión general sobre algunas de las otras opciones.

(3) DKP's makefile

Un makefile es un script usado para gestionar los archivos de un proyecto y los pasos necesarios para construir (build), limpiar (clean) o instalar un programa. Consisten en reglas que describen las dependencias entre los diferentes archivos de un proyecto y que comandos usar. La plantilla de los makefiles del devkitpro son practicamente automatizadas: todas las reglas relevantes ya están en su lugar y todo lo que tienes que hacer para añadir archivos fuente al proyecto es decirle al makefile en que directorios estan las fuentes. Basicamente, son maravillosos. Son también geniales para los usuarios novatos. Si te limitas a mantenerte en el procedimiento estandar todo debería funcionar bien, pero si quieres modificar la manera de hacer las cosas, aquí están las partes más importantes desde la perspectiva de un usuario.
El Makefile comienza tal que así:

#---------------------------------------------------------------------------------
# Clear the implicit built in rules
#---------------------------------------------------------------------------------

.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM)
endif

include
$(DEVKITARM)/gba_rules

#---------------------------------------------------------------------------------
# TARGET is the name of the output, if this ends with _mb a multiboot image is generated
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------

TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source
DATA :=
INCLUDES :=

#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------

ARCH := -mthumb -mthumb-interwork

CFLAGS := -g -Wall -O3\
-mcpu=arm7tdmi -mtune=arm7tdmi\
-fomit-frame-pointer\
-ffast-math \
$(ARCH)

CFLAGS += $(INCLUDE)

CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions

ASFLAGS := $(ARCH)
LDFLAGS = -g $(ARCH) -Wl,-Map,$(notdir $@).map

#---------------------------------------------------------------------------------
# path to tools - this can be deleted if you set the path to the toolchain in windows
#---------------------------------------------------------------------------------

export PATH := $(DEVKITARM)/bin:$(PATH)

#---------------------------------------------------------------------------------
# any extra libraries we wish to link with the project
#---------------------------------------------------------------------------------

LIBS := -lgba

#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------

LIBDIRS := $(LIBGBA)

## more ...

Esta parte del makefile establece ciertas variables que se usarán después. Las diversas variables -FLAGS son señaladores de compilación, ensamblaje y enlazador. No tienes que tocarlas, aunque puede que quiera usar -O2 en vez de -O3 ya que -O3 tiende a inflar el código severamente. La parte realmente importante es esta:

#---------------------------------------------------------------------------------
# TARGET is the name of the output, if this ends with _mb a multiboot image is generated
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
#---------------------------------------------------------------------------------

TARGET := $(shell basename $(CURDIR))_mb
BUILD := build
SOURCES := source
DATA :=
INCLUDES :=

Como dicen los comentarios, las variable SOURCE lista los directorios donde está tu código. En este caso, todo el código está en source. Si tienes código en otros directorios también, añadelos aquí separados por espacios. Si, espacios; esta es una de las razones por las que no usar espacios en las rutas como dijimos antes. Si tienes subdirectorios, utiliza barras inclinadas hacia adelante ('/'), no barras inclinadas hacia atrás ('\').
De igual forma, las variables DATA e INCLUDES son las que listan los archivos de los datos binarios y de las cabeceras. En este caso están vacios porque no hay datos o cabeceras adicionales. Los directorios son relativos a la localización del makefile; para indicar que la fuente esta en ese directorio, utiliza un punto ('.').

La linea TARGET es también interesante. Es el nombre del archivo de salida, sin ninguna extension. '$(shell basename $(CURDIR))' proporciona la última parte del directorio actual, que en este caso será template. En otras palabras, automaticamente usa el nombre del directorio del proyecto para el nombre de la ROM.
El '_mb' adicional indica que debería construirse como un juego multiboot. Hay dos tipos de construcciones GBA: cartucho y multiboot. La principal diferencia es donde reside el código y los datos. En un juego cartucho están en la ROM (32 MB); en uno multiboot están en la EWRAM (256 kb). Tecnicamente, cartucho es el tipo normal, pero multiboot puede funcionar con un cable multiboot.

Cartucho vs multiboot

Hay dos tipos diferentes de construcciones gba: 'cartucho' y 'multiboot'. Una construccion (build) cartucho coloca el código principal y los datos en la ROM de 32 MB (0800:0000h) de un cartucho. Una construcción multiboot lo pone en la EWRAM de 256 kb (0200:0000). Los juegos comerciales son obviamente construcciones cartucho, pero hacen uso de la construcción multiboot para hacer posible un multijugador con solo un cartucho.

A parte del tamaño máximo, hay poco diferencia entre ambos con respecto a la jugabilidad. Para aplicaciones caseras (homebrew), multiboot tiene una ventaja, ya que puedes cargar el juego en el hardware sin necesidad de usar un caro flashcart (cartucho flash); puedes construirte tu propio cable PC-GBA facilmente.

La selección del tipo de construcción se hace en la variable SPECS del makefile. Para construcciones cartucho hay que usar -specs=gba.specs y para construcciones multiboot -specs=gba_mb.specs. Si la variable TARGET termina con _mb, la plantilla del makefile lo enlazará como un juego multiboot.

(4) Cuando la compilación ataca

En la mayoría de los casos, los pasos dados hasta el momento funcionarán. Sin embargo, es posible que la instalación o la construcción no vaya de la manera en que debiera. Aquí esta un pequeño listado de los errores potenciales que pueden producirse en la construcción del proyecto template ('Hello World"):

'make not found'
También conocido como 'Failed to create process: The system cannot find the file specified.' o 'make: unknown command or filename' o cualquiera de las otras variantes. Esto significa que no se puede encontrar el comando make. Este debería estar en $(DEVKITPRO)/msys/bin, y esta ruta debería haberse añadido a la ruta (path) del sistema. Mira si make.exe está en el directorio correcto. Si está, chequea la ruta del sistema en 'My Computer/Advanced/Enviroment Variables/System Variables'. Como probablemente habrás deducido, esto es principalmente un problema de Windows.

'arm-eabi-gcc: no such file or directory'
make funciona, pero no puede encontrar al compilador. El compilador y otras herramientas están en $(DEVKITARM)/bin y el makefile añade eso a la ruta mediante 'export PATH := $(DEVKITARM)/bin:$(PATH)'. Asi que este error no debería ocurrir. DEVKITARM es una de las variables del sistema que la instalación crea; si has movido los directorios sin actualizar esta variable, este error ocurrirá. Es también posible que tengas una versión antigua de devkitARM; antes de la versión r19 el prefijo era arm-elf, no arm-eabi.

'This application has requested the Runtime to terminate it in an unusual way.'
Este es un error que en ocasiones obtengo cuando compilo con el Visual C++ IDE. No es un error del DKA (devkitARM), sino de Windows/MSVC. A la siguiente compilación siempre funciona.

Windows Vista
Este era un problema antes del devkitARM r21. Vista y GCC no se llevaban bien antes.

La construcción funciona; la ROM muestra una pantalla en blanco.
Por defecto, la pantalla de la GBA es blanca y si tienes un main() vacio, este será el resultado. Sin embargo, si estás seguro de que algo debería mostrarse, es probable que algo saliese mal, incluso antes de que tu código fuera llamado. Antes del main() el código de la ROM de arranque (bootcode) es llamado ($(DEVKITARM)/arm-eabi/lib/gba_crt0.s, por si tienes curiosidad), el cual se preocupa de algunos mantenimientos. Wintermute (el responsable de devkitPro) a veces hace pequeños ajustes en el código de arranque o en los linkscripts para mejorar el proceso, pero en ocasiones las cosas salen mal (perdón, Dave, saves que es verdad).
En el caso en el que hayas construido el proyecto template bajo devkitARM r21 exactamente tal como se vió antes y muestre una pantalla en blanco, es porque hay un bug en el linkscript para construcciones multiboot. La formas mas facil de arreglar esto es simplemente no construirlo como multiboot con el r21. Soluciones alternativas pueden encontrarse en http://forum.gbadev.org/viewtopic.php?t=14493.
Es algo sospechoso si alguna vez obtienes una pantalla en blanco despues de actualizar el devkitARM a pesar de que antes funcionaba. Normalmente hay un hilo en el foro de gbadev y es probable que si se trata de un error bootcode/linkscript no seas la primera persona en darse cuenta.

(5) Construyendo ejemplos Tonc con devkitARM

Todos las demos de Tonc y el código de la librería tonclib tienen proyectos PN2, así que es simplemente cuestión de abrirlos en el Programmer's Notepad 2 y presionar Alt+1.
Hay también archivos de proyecto para usar con Visual C++ 6 o superior. Estos hacen uso de un makefile maestro, tonc.mak. Este makefile sirve de hub para la construcción y limpieza individual o de todos los proyectos. Para proyectos individuales, establece en la variable DEMO el nombre de la demo que queremos construir. Desde MSVC, escoje la configuración correcta de construcción y construye como siempre. En la tabla de abajo tienes una visión general de las opciones.

to ... run ... MSVC config
build libtonc.a make libtonc Build libtonc
build foo demo make DEMO=foo Build Single
clean foo demo make DEMO=foo clean Clean Single
build all demos make build_all Build All
clean all demos make clean_all Clean All

[C] Entornos de desarrollo alternativos

DevkitARM es el conjunto de herramientas estandar para el desarrollo de aplicaciones casera (homebrew) para la GBA y casí la única que actualmente está activa/mantenida. El desarrollo con DKA implica C, C++ o ensamblador y la creación de todo desde cero (o al menos casi desde cero). Si quieres otro lenguaje o una API rica, estas alternativas merecen una oportunidad.

devkit Advance
Solo menciono esto aquí porque tecnicamente es aún una alternativa y la mayoría de los tutoriales aún se refieren a el. Devkit Advance es otro conjunto de herramientas basadas en GCC y puede ser considerado el predecesor de devkitARM. Hoy en día, no se me ocurre ninguna razón para usar devkit Advance en lugar de devkitARM quizás por la compatibilidad con los proyectos muy antiguos. Si sigues usandolo, deberías considerar la posibilidad de cambiarlo.

DKA vs DKA

Ambos devkitARM y devkit Advance son abreviados como "DKA", lo cual puede causar algo de confusión. No hay ninguna manera de saber a cual de los dos se refiere exceptuando quizás por la fecha: documentos anteriores al 2004/2005 se refieren a devkit Advance; los textos más recientes probablemente se referirán al devkitARM.

HAM, visualHAM y HEL
HAM es otro conjunto de herramientas basadas en GCC, pero también viene con HAMlib, una API para gestionar fondos, sprites y sonido. La instalación de windows también contiene una IDE llamada visualHAM.
Configurar HAM es facil: simplemente descarga la versión gratuita desde http://www.ngine.de e instalalo. Y después instalalo otra vez ya que es solo el instalador lo que has instalado :P. Después de la segunda instalación todo debería estar listo. Al igual que con DKA, no uses espacios en las rutas (paths).
HAM es util si no quieres involucrarte con las tripas de la programación de la GBA, pero aun así necesitas tener algo de idea de las funciones de la GBA para usar HAM apropiadamente. Ocultar los niveles más bajos puede ser peligroso en sistemas donde los recursos son excasos, como es el caso de la GBA. También me gustaría señalar que HAMlib no es exactamente eficiente cuando se trata de velocidad. Si estás usando HAM, obtén el add-on librería llamado HEL por Perter Schraut de http://www.console-dev.de. A diferencia de las muchas funciones de HAM, el código HEL ha sido optimizado para sacar el máximo partido a las capacidades de la GBA. HEL también está siendo mantenido.

HAM vs HEL

El creador de VisualHAM, Peter Schraut, ha escrito también un add-on librería llamado HEL. A diferencia de HAM, se ha dedicado algo de tiempo a optimizar el código de HEL, o al menos para no hacerlo lento. Si estás usando HAM, considera usar HEL también

Otros lenguajes
Hay algunos entornos no-C/asm para la GBA, pero hasta lo que yo se estos proyectos han sido en su mayoría abandonados por su creador original. Notese que mi conocimiento sobre estos paquetes es bastante limitado, así que no puedo hacer otra cosa que poner los enlaces a sitios donde podrás encontrarlos.
Está el dragonBASIC, el cual proporciona una sintaxis tipo BASIC. Debería ser adecuado para pequeños proyectos, pero no estoy seguro de que pueda ser usado para juegos completos como un clon de Mario. Puedes encontrar FreePascal para GBA/NDS en itaprograming.free.fr, y las instrucciones para usar Forth o LUA en www.torlus.com. Finalmente, hay (o había) algo llamado Catalpult en www.nocturnal-central.com. Este es un entorno completo con un emulador y creo haber visto un debugger también. Creo que podría ser comparado a GameMaker, pero de nuevo quizás esté equivocado.

[D] Detalles de la linea de comando

Esta sección tiene dos propósitos: para dar a aquellos que usan unicamente GUIs algo de información sobre como trabajar con la linea de comandos (y como no trabajar con ella). Ahora, esto debería ser un tema para un apéndice si no fuera por como están estructurados los anteriores capítulos y sus ejemplos.

(1) Trabajando con la linea de comandos

Para la mayoría de la gente de hoy en día, trabajar con programas significa doble-click en el enlace del escritorio o doble-click en un archivo en el Explorer (me estoy refiriendo a los que utilizan Windows. Perdón a el otro 10%). Para trabajos de oficina esto suele ser suficiente. Para el trabajo de desarrollo (en particular el desarrollo de consola), vale la pena tener una comprensión más profunda de lo que está pasando.
La mayor parte de esta subsección tendrá un alto factor ¡duh!. Sientase libre de saltarsela si le es familiar.

Como cualquier otro archivo, los archivos de programa (ejecutables) están almacenados en algún lugar de la jerarquía de archivos. Por ejemplo, el ejecutable principal del Office Word se llama winword.exe y podría encontrarse en C:/Program Files/(... Más Directorios ...)/winword.exe. El nombre de la ruta es también el comando para ejecutar el programa: simplemente pasa la ruta a la consola (shell) y el SO ejecutará el programa. Normalmente esto se hace mediante accesos directos: doble-click en un acceso directo le dirá a la GUI que ejecute el objetivo asociado. También puedes invocarlo via la linea de comandos. En el Menu Inicio, puedes encontrar Ejecutar (Run)... Introduciendo winword allí lanzará Office Word, al igual que hizo el doble-click.

Imagen
Menú Inicio -> Ejecutar.

Los programas suelen permitir opciones en la línea de comandos, separados por espacios. Los tipos de opciones disponibles dependen del programa en cuestión, por supuesto. Para Office Word, la opción principal es pasar el nombre de un fichero a abrir. Por ejemplo,

winword "C:\foo\bar.doc"

abrirá el fichero C:\foo\bar.doc. Lo mismo ocurre cuando haces doble-click en un documento Word: Windows coje el nombre del fichero, mira que aplicación está asociada a ese archivo y llama a la aplicación con el nombre del fichero como opción.

El valor de la linea de comandos
Por supuesto, usar la linea de comandos para abrir un documento Word puede parecer un poco tonto considerando que puedes hacer lo mismo simplemente haciendo doble-click en el archivo, pero hay casos en los que es interesante. Por ejemplo, puedes usarla para abrir multiples documentos a la vez ('winword C:\a.doc C:\b.doc') o mandarlo a imprimir, o cualquier cosa que te permita ese programa. Las GUIs pueden ser faciles en ocasiones, pero usar la linea de comandos permite un mayor control.
Una segunda cosa genial de usar la linea de comandos es que puedes automatizar procesos. Esto es particularmente importante en programación, porque generalmente involucra ejecutar multiples pasos para cada archivo del proyecto. Hacer todo esto manualmente para cada archivo del proyecto y cada vez que reconstruyas va mas alla de cualquier consideración racional; querrás un script para eso. Los archivos batch y los makefiles son ejemplos de ese tipo de scripts.

Pasos básicos para construir un proyecto de GBA
Convertir tu fuentes C/C++/asm en binarios GBA válidos requiere de los siguientes cuatro pasos:

1.- Compilar/ensamblar las fuentes. El primer paso es convertir los archivos de formato legible C o C++ (.c/.cpp) o los archivos en ensamblador (.s/.asm) a formato binario conocido como archivos objeto (.o). Hay un archivo objeto para cada archivo fuente.
La herramienta para llevar a cabo esto se llama arm-eabi-gcc. En realidad, es solo un front-end del compilador real, pero esos son solo detalles. Aquí arm-eabi- es solo un prefijo especifico de devkitARM; otros conjuntos de herramientas o plataformas tienen diferentes prefijos. Notese que C++ usa g++ en vez de gcc.
2.- Enlazar los archivos objetos. Despues de lo anterior, necesitas enlazar los archivos objetos separados en un archivo ELF ejecutable. Cualquier librearía de código precompilada (.a) que puedas tener se enlazan en esta etapa.
Puedes compilar y enlazar/vincular a la misma vez, pero es una buena práctica mantener separados los procesos: los proyectos serios normalmente contienen multiples archivos y no querrás tener que esperar todo un mundo en recompilarlo cuando solo has cambiado uno. Esto se hace aún más importante cuando empiezas a añadir datos (gráficos, música, etc).
Una vez más, arm-eabi-gcc es usado para invocar al enlazador, aunque el enlazador real se llama arm-eabi-ld.
3.- Traducir a ejecutable puro. El archivo ELF aun contiene datos de depuracion (debug) y no puede ser leido por la GBA (aunque la mayoría de los emuladores lo aceptarán). arm-eabi-objcopy arranca los datos depurados y se asegura de que la GBA lo aceptará. Bueno, casi.
4.- Validar la cabecera. Cada juego de la GBA tiene una cabecera con unos chequeos para segurarse que es un binario GBA válido. Normalmente, la compilación no proporciona ninguno, asi que tenemos que usar una herramienta como DarkFader's gbafix para corregir la cabecera. Esta herramienta viene con el DKA, asi que no tienes que descargarla por separado.

La demo de el siguiente capítulo se llama first, la cual usa solo un código fuente, first.c. Para crear el binario first.gba, necesitarás ejecutar los siguientes comandos:

# Compilar first.c a first.o
arm-eabi-gcc -mthumb -mthumb-interwork -c first.c

# Enlazar first.o (y las librerías estandar) a first.elf
arm-eabi-gcc -specs=gba.specs -mthumb -mthumb-interwork first.o -o first.elf

# Strip a solo-binario
arm-eabi-objcopy -O binary first.elf first.gba

# Arreglar (fix) la cabecera
gbafix first.gba

Nótese que aparte de los nombres de los archivos (en negrita), también hay diferentes opciones de las herramientas (cualquier cosa que comience con un guión). Las opciones en cursiva son tecnicamente no necesarias, pero no obstante recomendables. He recojido algunas de las señalizaciones (flags) más comunes en el apéndice del makefile, así que hechales un vistazo si quieres conocerlas. Puedes ver la lista completa de opciones en los manuales, aunque debo advertirte que el número de opciones es bastante extenso.

El enlazador/vinculador de devkitARM necesita una opción -specs.

A diferencia de los otros conjntos de herramientas, devkitARM requiere que o -specs=gba.specs o -specs=gba_mb.specs este presente como opción de enlace. Estas specs contienen el mapa de memoria sin el cual el enlazador no puede hacer su trabajo. Si estás migrando desde un conjunto de herramientas antiguo y encuentras que de repente el binario no funciona, probablemente esta sea la causa.

Es buena idea la de siempre tener -mthumb -mthumb-interwork en las indicaciones del compilador y del enlazador. Activar la optimización del compilador (por ejemplo -O2) y los avisos (-Wall) es de ayuda también.

Mejor vivir a traves de la automatización
Puedes construir un binario de GBA escribiendo de cada vez los comandos visto arriba en una linea de comandos. También es posible limpiar los cuartos de baño con un cepillo de dientes antes de usarlo en tus dientes - solo porque puedas hacerlo no siempre significa que debas hacerlo. Introducir manualmente cada linea cada vez que quieras reconstruir algo es, bueno, insano. Es mucho más útil usar algún tipo de script para que lo haga por tí. Tecnicamente, puedes usar cualquier tipo de entorno de script que quieras, pero yo me centraré en dos en particular: archivos batch y makefiles.
Los archivos batch (batch-files .bat) son script de la consola de Windows que existen desde el antiguo MS-DOS. Los archivos batch son muy faciles de usar: simplemente escribe los comandos en un archivo .bat y ejecutalo. Mientras que los archivos batch son faciles de usar, son totalmente insuficientes para todo menos para los proyectos simples. Proyectos más complejos tendrán múltiples archivos y añadir lineas de compilación extra cada vez que añades un archivo es una molestia. Para ser justos, es posible usar variables y bucles y cosas así en los archivos batch para aliviar esta situación, pero nadie los menciona nunca.
Otro problema es que si ejecutas un archivo batch, se ejecuta entero. Esto significa que estas compilando todos los ficheros cada vez, y si hay errores, obtendrás los errores para todos los archivos del proyecto. Esto puede ser un inconveniente a la hora de navegar por ellos y a veces puede que no sea posible debido a que los primeros errores hayan pasado el límite del scroll (esto era cierto para las versiones de Windows 98 y las anteriores, las cuales incluso no tenían una barra de scroll en la ventana del DOS. ¡Eeek!).
Finalmente, la sintaxis de los archivos batch son solo para DOS/Windows. Esto los hace no aptos para el desarrollo en plataformas independientes.

Una solución mejor es usar makefiles. Makefiles son script que se ejecutan mediante una herramienta llamada make (la cual Windows, por lo general no tiene, pero viene con MSys). Los makefiles no dependen de la plataforma y make gestiona los ficheros facilmente mediante el trabajo con reglas en lugar de solo comandos. Puedes tener un patrón de reglas que te diga como convertir un archivo de un tipo a otro (como compilar archivos .c en archivos .o) y make se hará cargo de todo; todo lo que necesitas hacer es proporcionar un listado de los ficheros que necesitan ser compilados. Make también comprobará en primer lugar si es necesaria la compilación por lo que el trabajo innecesario no se llevará a cabo si el archivo de salida está actualizado.
El problema con los makefiles es que son más difíciles de crear que los archivos batch - al menos para los no iniciados. Pero gracias a la plantilla de los makefiles de devkitPro, por lo general no tendrás que preocuparte por nada: simplemente establece los directorios correctos y listo. Aún así, vale la pena aprender un poco más sobre como trabajan los makefiles. Por esa razón, la siguiente sección explicará un poco más el proceso de los makefiles. Los ejemplos de Tonc también tienen makefiles que van aumentando en complejidad.

Si estás preocupado de que los makefiles no se pueden ejecutar con doble-click, siempre puedes crear un archivo batch que ejecute el makefile. Algo como esto debería ser suficiente.

REM batch-file to run make
make
pause

No empieces este archivo batch con 'make clean', ya que eso forzará a una completa reconstrucción - algo que estamos intentando evitar... También aconsejo no llamarlo make.bat, ya que puede entrar en conflicto con el nombre de la herramienta make.

Aún así no recomiendo este método. El archivo batch se ejecutará en la ventana de DOS, en la cual la navegación por ella no es buena. Sería mejor utilizar un bloc de notas que pueda ejecutar comandos de consola y capturar su salida. La mayoría de estos también te permitirán ir a los errores mediante doble-click en el mensaje de error. PN2 es uno de los muchos editores que permiten hacer esas cosas.

Escoje los makefiles sobre los archivos batch

A pesar de su facilidad, usar los archivos batch solo te causarán complicaciones a largo plazo. Es mejor usar algo que pueda hacer frente a proyectos complejos.

Algo malo de los makefiles es que no puedes activarlos mediante doble-click. Es posible crear un archivo batch que invoque al makefile, pero una mejor opción sería utilizar un editor de código que también pueda ejecutar comandos en consola.

Rutas y variables del sistema
Si intentas construir cualquier cosa usando los comandos dados anteriormente, probablemente descubrirás que no funciona. Esto es porque omití una información importante: la ruta (path). Para que la consola pueda ejecutar comandos, necesita primero encontrar la ruta del mismo y no sirve simplemente con usar arm-eabi-gcc ya que el archivo está en realidad en .../devkitPro/devkitARM/bin/arm-eabi-gcc. La ruta completa necesita ser visible para la consola, no solo el nombre del archivo.
Debido a que escribir todo es bastante problemático y porque mi estructura de directorios puede ser diferente a la tuya, el sistema operativo tiene una variable llamada PATH para directorios estandar. Si solo das el nombre del archivo, la consola buscará una coincidencia en el directorio actual y en todas las rutas en PATH.
Es posible añadir el directorio bin de DKA a PATH directamente, pero devkitPro opta por un aproximación más limpia. En vez de añadirlo a PATH, el instalador crea un número de variables de entorno a algunos de los directorios principales, los cuales puedes usar durante el proceso de construcción para apuntar a la ruta real. Por ejemplo, hay una variable DEVKITARM, que en mi caso equivale a /e/dev/devkitPro/devkitARM. La tuya probablemente sea algo diferente, pero lo importante es que en ambos casos $(DEVKITARM)/bin será el directorio donde la principales herramientas estén.

Nótese que el formato estandar de Windows para los directorios es algo como c:/foo/bar, mientras que la variable DEVKITARM tiene el formato de una ruta POSIX con barras inclinadas hacia adelante. Hasta lo que yo se, Windows es el único sistema operativo que no permite nombres con POSIX lo cual, bueno, apesta. Aquí es donde MSys entra en juego. MSys es una colección de herramientas para hacer que las herramientas estandar UNIX estén disponibles en sistemas DOS/Windows. A parte de la herramienta make, también lleva la consola bash en donde puedes usar nombres POSIX como en cualquier otro programador. Para cambiar a bash en DOS, escribre 'sh'. En general, bash es una consola mucho más útil que DOS, aunque puede que te tengas que acostumbrar al diferente conjunto de instrucciones. Pero esa es la razón por la que tenemos manuales.

(2) Makefiles básicos

Como los archivos batch, los makefiles son scripts que pueden ayudarte a construir un proyecto. La principal diferencia en como trabajan es que los archivos batch utilizan una lista secuancial de comandos, mientras que los makefiles usan una cadena de reglas que definen como los archivos se convierten en otros. Este es el formato básico de una regla:

# Ejemplo de una regla de un makefile
objetivo : prerequisitos
comandos

El objetivo puede ser el fichero o ficheros de salida, o simplemente un identificador de la regla, los prerequisitos son los archivos de los que depende el objetivo y los comandos son un listado de comandos que convierten los prerequisitos en el objetivo (aunque tecnicamente son capaces de hacer otras cosas también). Tenga en cuenta que la sangría (márgenes) de los comandos deben estar tabulados (ASCII 9). Este es un requisito un poco molesto cuando copias y pegas makefiles, así que recuerdalo bien.
El equivalente directo a los comandos usados antes para construir first.gba sería algo así:

#
# Makefile equivalente al proceso de construcción anterior.
#


PATH := $(DEVKITARM)/bin:$(PATH)

first.gba : first.c
arm-eabi-gcc -mthumb -mthumb-interwork -c first.c
arm-eabi-gcc -specs=gba.specs -mthumb -mthumb-interwork first.o -o first.elf
arm-eabi-objcopy -v -O binary first.elf first.gba
gbafix first.gba

Aquí solo hay una regla, con objetivo first.gba y prerequisito first.c. Los comandos son el resto (tabulados).

Tabulaciones, no espacios, antes de los comandos

NOTA: Los make de GNU requieren tabulación antes de los comandos, no espacios. Si copias y pegas, tendrás que poner las tabulaciones manualmente.

Ejecutar makefiles
Puedes invocar a make para que ejecute el makefile así:

make -f nombre_del_archivo nombre_del_objetivo

La señalización '-f' indica que makefile ejecutar; el nombre del objetivo dice con que regla empieza la cadena. Ambas opciones son opcionales. Sin la opción '-f', make buscará en el directorio actual archivos con el nombre 'GNUmakefile', 'Makefile' o 'makefile' y lo ejecutará. Este es el porque los makefiles se suelen llamar 'Makefile'. Si el nombre del objetivo está ausente, la cadena empieza en la primera regla del fichero.
No es necesario que te desplaces a la linea de comandos y escribas 'make': Los IDEs a menudo lo harán por tí, aunque configurar el IDE para eso puede llevar algo trabajo. No lo voy a cubrir aquí, googlea o usa los archivos de ayuda para averiguar que necesitas hacer para conseguirlo en tu editor. Tengo ejemplos para configurar conTEXT, una alternativa de PN, y MS Visual Studio en el apéndice. La web del DKP también tiene varios ejemplos en este FAQ.

Makefiles, versión 2
El makefile mostrado arriba era un ejemplo extremadamente simple (y limitado) de que aspecto tendría. Un makefile decente tiene múltiples reglas y usa variables para definir los datos comunes utilizados. El siguiente ejemplo es más complejo, pero también más útil.

#
# A more complicated makefile
#


PATH := $(DEVKITARM)/bin:$(PATH)

# --- Project details -------------------------------------------------

PROJ := first
TARGET := $(PROJ)

OBJS := $(PROJ).o

# --- Build defines ---------------------------------------------------

PREFIX := arm-eabi-
CC := $(PREFIX)gcc
LD := $(PREFIX)gcc
OBJCOPY := $(PREFIX)objcopy

ARCH := -mthumb-interwork -mthumb
SPECS := -specs=gba.specs

CFLAGS := $(ARCH) -O2 -Wall -fno-strict-aliasing
LDFLAGS := $(ARCH) $(SPECS)

.PHONY : build clean

# --- Build -----------------------------------------------------------
# Build process starts here!
build: $(TARGET).gba

# Strip and fix header (step 3,4)
$(TARGET).gba : $(TARGET).elf
$(OBJCOPY) -v -O binary $< $@
-@gbafix $@

# Link (step 2)
$(TARGET).elf : $(OBJS)
$(LD) $^ $(LDFLAGS) -o $@

# Compile (step 1)
$(OBJS) : %.o : %.c
$(CC) -c $< $(CFLAGS) -o $@

# --- Clean -----------------------------------------------------------

clean :
@rm -fv *.gba
@rm -fv *.elf
@rm -fv *.o

#EOF

La parte superior de este makefile se utiliza para definir variables para su uso posterior. Algo como 'FOO := bar' define una variable llamada FOO que puede ser usada via $(FOO). Aunque solo estoy usando :=, hay otros métodos también:

= Substitución directa de variable (como una mcro en C).
:= Variable básica (sobreescribe la definición anterior).
?= Crea una variable si esta no existe ya.
+= Añade a la variable existente.

La mayoría de las variables creadas aquí son cosas estandar: nombres para el compilador y el enlazador (CC y LD) y sus señaladores/indicadores (CFLAGS y LDFLAGS). Estos no son estrictamente necesarios, pero son útiles. Las cosas realmente relacionadas con el proyecto son TARGET y OBJS. TARGET es el nombre base de el binario de salida, y OBJS es la lista de archivos objeto. Nota: ¡lista de los objetos!, ahora mismo hay solo un archivo, pero proyectos posteriores tendrán multiples archivos fuentes que tendrán que ser compilados y enlazados. Usando ese tipo de variables, añadir un nuevo archivo al proyecto es solo cuestión de extender esta lista. Las reglas de inicio están basados en nombres de objetivo, no de prerequisito.
Hay también mas reglas. Las principales reglas son de construcción y limpieza (la variable .PHONY es solo para indicar que no son realmente nombres de archivos). En la regla de construcción puedes ver como funciona la asociación: build depende del binario .gba, el cual depende del archivo .elf, el cual depende del archivo objeto, el cual depende del archivo fuente. Son basicamente los pasos básicos que dí antes pero en sentido inverso.
Parte de la magia de los makefile es que una regla solo se ejecutará si los prerequisitos son más jovenes que los objetivos. Por ejemplo, si un particular archivo fuente ha sido modificado, será más joven que los es el archivo .o y la regla de compilación se ejecutará para ese archivo en particular pero no para los otros. Esta es una de las razones de porque dividir los procesos en reglas separadas es útil.
Las cosas con un simbolo de dolar ($@, etc) son variables automáticas. Se trata de abreviaciones para los nombres de los objetivos y los prerequisitos. Puedes saber que significan en la siguiente tabla; para una lista completa, ve al manual del make.

$< Nombre del primer prerequisito
$^ Lista de todos los prerequisitos
$@ Nombre del objetivo

La última cosa que quiero discutir aquí concerniente a este makefile particular es la regla de la compilación. La forma '%o : %.c' es un ejemplo de un regla estática. Basicamente dice "para todos los archivos en OBJS con la extensión '.o', mira el archivo correspondiente '.c' y ejecuta el comando". Como dije anteriormente, OBJS puede tener multiples nombres de archivo, cada uno de los cuales se compilará automaticamente via esta regla. Una vez más, esta es una de las cosas buenas de los makefiles: para añadir un archivo al proyecto, no necesitas escribir otra regla, simplemente añade el nombre del objeto a OBJS y listo. También hay posibilidades de obtener todos los archivos de un directorio para no tenerlos que añadir tu a mano, pero ese tema está fuera de esta sección.

(3) La estructura de Tonc

Esta última sección no debería estar realmente aquí. Con las plantillas de los makefiles de devkitPro, administrar proyectos debería ser suficientemente facil sin tener que saber nada sobre los makefiles, por lo que esto se podría haber metido en un apéndice. Así que, ¿por qué está aquí?.
La razón es de caracter histórico. Cuando empecé sobre el año 2004, devkitARM erá aún joven y libgba, el instalador y las plantillas simplemente no existían aún. Había un puñado de tutoriales de GBA los cuales explicaban lo básico, pero todos utilizaban pobres (algunas veces muy pobres) estandares de programación y una pobre estructura de proyecto. Con esto último me refiero a tres cosas:

- usando erroneos indicadores de compilación;
- #incluyendo todo el programa en un solo archivo (este tema se cubre con más detalle en la sección de datos en el capítulo de bitmaps);
- usando archivos batch en vez de makefiles;
- el código era simplemente incorrecto o muy ineficiente.

En vez de solo decir como se hacen las cosas, también he tratado decir como no se hacen las cosas. Sabiendo lo que hay que evitar puede ser tan importante como saber los movimientos correctos. También he intentado hacer una introducción facil a los makefiles para que no parezcan tan complicados para los nuevos usuarios. Esto se tradujo en dividir Tonc en tres partes principales:

- Básico: proyectos independientes por completo; con makefiles muy simples.
- Extendido: los proyectos hacen uso de tonclib; makefiles más complejos.
- Avanzado: los proyectos hacen uso de tonclib y los makefiles derivan de los makefiles de devkitPro.

En la sección 'básico', he gastado mucho tiempo explicando sobre las prácticas buenas/malas. Requiere conocimiento elemental de los makefiles, lo que se ha visto en esta sección. Si tuviese tiempo o si realmente fuese necesario hubiera hecho las cosas de diferente manera, pero el requerimiento de las buenas/malas prácticas han hecho que las anteriores partes fueran más difíciles de mantener que los capítulos posteriores. Una pequeña ironía de la vida.