Primeros pasos
Requisitos
- Delphi 12+ (Athens) — necesario para los literales de cadena multilínea (
'''), que usan cinco units enviadas - Windows — Win32 y Win64. Ningún paquete declara un objetivo Linux
Instalación
DAF se distribuye como fuente: un conjunto de paquetes Delphi (.dpk). Cada release de GitHub lo trae en un zip, Source code (zip) en los Assets de la release: https://github.com/Delphi-DAF/dafce/releases. Descomprímelo donde quieras, también en una ruta con espacios, y ejecuta desde esa carpeta todo lo que sigue. O clona el repo:
git clone https://github.com/Delphi-DAF/dafce.gitCompilar los paquetes
Cada proyecto toma sus rutas de salida de src/paths.optset, que las deriva todas de PRJ_OUT_DIR. BDS.bat fija esa variable a partir de su propia ubicación, así que el IDE se arranca a través de él:
BDS startEso abre RAD Studio con el entorno del proyecto y carga src/DAFGroup.groupproj. Un IDE arrancado de cualquier otra forma deja PRJ_OUT_DIR sin definir, y todas las rutas de salida se construyen entonces sobre un valor vacío. BDS inspect imprime lo que hay fijado; las variables del proyecto viven en project.cmd, y los ajustes por máquina en un %COMPUTERNAME%.project.cmd al lado.
BDS.bat guarda el perfil del IDE de cada carpeta bajo HKCU\Software\Embarcadero\DAF\<nombre de la carpeta>. Borrar la carpeta deja esa clave, y reg delete "HKCU\Software\Embarcadero\DAF\<nombre de la carpeta>" /f la quita.
Desde la línea de comandos no hay nada que preparar — los dos scripts llaman a BDS.bat por su cuenta:
buildall.bat all
runtests.bat allSin opciones, buildall.bat compila el framework en Debug y Release, y después los samples y las specs en Debug. Estas opciones compilan solo una parte, y se combinan:
| Opción | Compila |
|---|---|
--framework |
el framework, en Debug y Release |
--samples |
el framework en Debug, y después los samples |
--specs |
el framework en Debug, y después las specs |
runtests.bat ejecuta todas las suites que declara el grupo de specs. Los dos aceptan Win32, Win64 o all, y buildall.bat acepta además --clean, que borra out/ antes de empezar.
Elegir la versión de Delphi
project.cmd elige Delphi 13 (PRJ_IDE=D370). Delphi 12 es PRJ_IDE=D290, y cualquiera de estas dos formas lo elige sin editar project.cmd:
- un
%COMPUTERNAME%.project.cmdjunto aproject.cmd, con la líneaset "PRJ_IDE=D290"; set "PRJ_IDE=D290"en su propia línea en la consola, antes de lanzarbuildall.bat.
Con Delphi 12, buildall.bat --framework --samples compila el framework y los samples. Las specs del módulo VCL necesitan Delphi 13, así que --specs, y buildall.bat sin opciones, acaban en BUILD FAILED.
Si la versión pedida no está instalada, BDS.bat no compila nada, sale con código 2 y lista las versiones instaladas con el PRJ_IDE de cada una.
Usar lo compilado
Añade out\Win32\Release\lib o out\Win64\Release\lib al search path de tu proyecto, y las units de DAF que use tu programa compilan contra esa carpeta. out\<Platform>\Debug\lib tiene las mismas units compiladas en Debug, para depurar.
Usar el fuente directamente
Añadir las rutas src/[Module]/ que necesites al search path de tu propio proyecto compila esas units con las rutas de salida de tu proyecto, así que nada de lo anterior aplica. Cada módulo es autocontenido.
Tu primera aplicación DAF
Esto es el sample QuickStart tal cual — es el fichero que lee el compilador, y un check compara los dos, así que lo que copies de aquí es lo que compila:
program QuickStart;
{$APPTYPE CONSOLE}
uses
Daf.Extensions.DependencyInjection,
Daf.CommandLine,
Daf.Configuration.CommandLine,
Daf.Cli;
// El ejemplo de entrada de una herramienta de linea de comandos: el builder, la accion de la raiz
// escrita en el sitio, los argumentos que recibe la gramatica, y el codigo de salida que devuelve
// esa accion.
//
// QuickStart -> 0, saluda
// QuickStart --help -> 0, la ayuda
//
// Como se anade un servicio esta en el sample ServiceWiring, que es el nivel siguiente.
begin
var B := TCliApplication.CreateBuilder(CommandLineConfig.ProcessArgs);
B.SetAction(
function(const Services: IServiceProvider; const Parsed: IParseResult): Integer
begin
Writeln('Hola desde DAF');
Result := TCliExit.Ok;
end);
B.ParseArgs(CommandLineConfig.ProcessArgs);
ExitCode := B.Build.Run;
end.Tres cosas sobre la forma, y las tres se equivocan con facilidad:
- El builder se sostiene en una variable, no en una cadena, y los registros ocurren donde están escritos: no hay callback diferido
ConfigureServices.TCliApplication.CreateBuilderdevuelve unICliApplicationBuilder, cuyoBuilddevuelve elICliApplicationcuyoRunes el código de salida. - Los argumentos van a dos llamadas, y cada una alimenta a un lector:
CreateBuilderlos añade a la configuración, yParseArgsse los da a la gramática, que contesta--helpsin ninguna opción declarada. SinParseArgs, la gramática parsea una invocación vacía. Daf.Extensions.DependencyInjectionestá en elusesaunque no se registre nada: la firma de la acción nombraIServiceProvider, y Delphi exige que el tipo esté visible para escribirla.
Añadir un servicio
El sample ServiceWiring es el mismo programa con un servicio registrado y resuelto:
program ServiceWiring;
{$APPTYPE CONSOLE}
{$STRONGLINKTYPES ON}
uses
System.SysUtils,
Daf.Extensions.DependencyInjection,
Daf.CommandLine,
Daf.Configuration.CommandLine,
Daf.Cli,
ServiceWiring.Greeter in 'ServiceWiring.Greeter.pas';
// Como entra un servicio en una herramienta de linea de comandos: se registra en el builder, que
// ya esta vivo, y la accion lo resuelve del proveedor que recibe.
//
// ServiceWiring -> 0, saluda a traves del servicio
begin
var B := TCliApplication.CreateBuilder(CommandLineConfig.ProcessArgs);
B.Services.AddSingleton<IGreeter, TGreeter>;
B.SetAction(
function(const Services: IServiceProvider; const Parsed: IParseResult): Integer
begin
Writeln(Services.GetRequiredService<IGreeter>.Greet);
Result := TCliExit.Ok;
end);
B.ParseArgs(CommandLineConfig.ProcessArgs);
ExitCode := B.Build.Run;
end.Servicesresponde antes de construir nada, así que elAddSingletonsurte efecto donde está escrito, y la acción que declaraSetActionresuelve del proveedor que recibe.- El servicio vive en su propia unit. Un tipo declarado en el
.dprno está en la seccióninterfacede ninguna unit, y resolverlo falla en ejecución conENonPublicType. Es también por lo que el programa lleva{$STRONGLINKTYPES ON}: sin él el enlazador descarta la RTTI por la que el contenedor resuelve.
Hay un segundo punto de entrada, más abajo: THostBuilder, del módulo Hosting, para cuando quieres el host sin la capa de aplicación alrededor, con Hosting/samples/HostQuickStart como su propio ejemplo de entrada. La guía de la familia de aplicaciones dice qué te da cada uno.
Mapa de módulos
| Si necesitas… | Usa el módulo |
|---|---|
| Contenedor DI | DependencyInjection |
| Ciclo de vida de la app | Hosting |
| Ficheros de config / env vars | Configuration |
| Logging estructurado | Logging |
| Comandos / queries | MediatR |
| Specs BDD / tests | MiniSpec |
| Logging estilo NLog | NNLog |
| Smart pointers / RTTI | Commons |
| Servidor HTTP / routing | Web |
Próximos pasos
- Lee el resumen de arquitectura
- Explora la referencia de módulos
- Revisa la carpeta
samples/del repo para ejemplos ejecutables